Indian Scale tuner

need a feature, suggest here

Re: Indian Scale tuner

Postby Broomy » Thu Nov 16, 2017 9:49 am

I will also check the last part of the johnston tuner.
I could rewrite the shrutituner in the same format as the johnston and diatonic tuner.

As a to do list for myself:
- Alter the comments in the diatonic tuner section, to make it generic "manual" to use for other presets
- Clean up the johnston code (comments and formulas)

Hans
User avatar
Broomy
 
Posts: 194
Joined: Thu Apr 24, 2014 7:53 am

Re: Indian Scale tuner

Postby Broomy » Thu Nov 16, 2017 12:19 pm

1. Because we are in an logarithmic environment, it maybe more accurate to calculate the difference between two intervals as follows: difference=(ratio1xratio2)^1/2.


After some research, the proper way to calculate the log-average is:
ratioav = b^((logb(ratio1)+logb(ratio2))/2)
b = lognumber (10, 2 or e)

So making a variable dif_freq which is derived from
ratiodif = 2 - (RatioHighestNote*2)^1/2


Becomes:
ratiodif = 2 - b^((logb(RatioHighestNote)+logb(2))/2)
User avatar
Broomy
 
Posts: 194
Joined: Thu Apr 24, 2014 7:53 am

Re: Indian Scale tuner

Postby brummer10 » Thu Nov 16, 2017 1:53 pm

I'm eager to see with what you coming up. :)
I'll set a watch on your fork.
User avatar
brummer10
Site Admin
 
Posts: 782
Joined: Thu Mar 26, 2009 6:57 pm

Re: Indian Scale tuner

Postby Broomy » Thu Nov 16, 2017 6:16 pm

My goal is to make a more generic way make different tuner presets.
I also want to get rid of the need of a spreadsheet to calculate stuff.

I would like to start a preset with two strings:
1. Note names
2. Ratio (one ratio per notename + 2/1)

Then count the number of note names and store that as a variable.
Then find the last ratio in the string to use it for calculating the ratiodifference for setting the right octave.

I'm pondering over a way to make some kind of loop when checking which note to use instead of a set of "else if" statements. If that's possible then it doesn't matter how many notes there are in the scale, it keeps looping one note up till the right note is found for n=0 till n=numberofnotenames. That would reduces the number of lines of code drastically and it's a lot faster to add a new tuner preset.
(if this way of looping works it might also work for setting the right octave).

Right now I'm gonna dive into C++ manuals...

@Hermann: If you know that this idea isn't doable with C++ let me know!

Hans

Edit:

Would something like this work? (in pseudocode )
Code: Select all
for (int n=0 ; n=NumberOfNotes ; n++ )
     { //here we calculate the needed stuff
       int ratiodiff = 10^((log(StringOfRatio[n])+log(StringOfRatio[n+1])/2)
             if (percent < ratiodiff) {
                 display_note = n
                 scale = ((percent-StringOfRatio[n]))/2.0;
             }
       }
User avatar
Broomy
 
Posts: 194
Joined: Thu Apr 24, 2014 7:53 am

Re: Indian Scale tuner

Postby brummer10 » Thu Nov 16, 2017 7:59 pm

Broomy wrote:@Hermann: If you know that this idea isn't doable with C++ let me know!


Oh, it is. And you are right, it will reduce the lines of code and makes it easier to maintain and add new mods.
Broomy wrote:Would something like this work? (in pseudocode )

Code: Select all
 for (int n=0 ; n=NumberOfNotes ; n++ )
         { //here we calculate the needed stuff
           int ratiodiff = 10^((log(StringOfRatio[n])+log(StringOfRatio[n+1])/2)
                 if (percent < ratiodiff) {
                     display_note = n
                     scale = ((percent-StringOfRatio[n]))/2.0;
                 }
           }


Yes, this idea looks good so far,
User avatar
brummer10
Site Admin
 
Posts: 782
Joined: Thu Mar 26, 2009 6:57 pm

Re: Indian Scale tuner

Postby Broomy » Thu Nov 16, 2017 9:13 pm

I've tried to alter some code on the diatonic tuner. I can do "make" and "make install", but when I choose diatonic, gxtuner freezes. Is there a way to debug this / see where it freezes?

here's the code:
Code: Select all
// copy the following block and edit it to your needs to add a new tuning mode
static gboolean gtk_tuner_expose_diatonic(GtkWidget *widget, cairo_t *cr) {
    // Note names for display
    static const char* diatonic_note[] = {"Do","Re","Mi","Fa","Sol","La ","Ti"};
    float noteratio[] = {1/1, 9/8, 5/4, 3/2, 4/3, 5/3, 15/8, 2/1};
    int numberofnotes = (sizeof(noteratio) - 1) ;
   
    // Frequency Octave divider
    float multiply = 1.0;
    // ratio
    float percent = 0.0;
    // Note indicator
    int display_note = 0;
    // Octave names for display
    static const char* octave[9] = {"0","1","2","3","4","5","6","7"," "};
    // Octave indicator
    static int indicate_oc = 0;
   
    GxTuner *tuner = GX_TUNER(widget);
    // fetch widget size and location
    GtkAllocation *allocation = g_new0 (GtkAllocation, 1);
    gtk_widget_get_allocation(GTK_WIDGET(widget), allocation);

    double x0      = (allocation->width - 100) * 0.5;
    double y0      = (allocation->height - 60) * 0.5;

    static double grow   = 0.;

    if(allocation->width > allocation->height +(10.*grow*3)) {
        grow = (allocation->height/60.)/10.;
    } else {
        grow =  (allocation->width/100.)/10.;
    }
   
    tuner->scale_h = (allocation->height/60.)/3.;
    tuner->scale_w =  (allocation->width/100.)/3.;
    // translate widget size to standart size
    cairo_translate(cr, -x0*tuner->scale_w, -y0*tuner->scale_h);
    cairo_scale(cr, tuner->scale_w, tuner->scale_h);
    cairo_set_source_surface(cr, GX_TUNER_CLASS(GTK_WIDGET_GET_CLASS(widget))->surface_tuner, x0, y0);
    cairo_paint (cr);
    cairo_restore(cr);

    cairo_save(cr);
    cairo_translate(cr, -x0*tuner->scale_w*3., -y0*tuner->scale_h*3.);
    cairo_scale(cr, tuner->scale_w*3., tuner->scale_h*3.);
   
   
    // fetch Octave we are in,
    float scale = -0.4;
    if (tuner->freq) {
        // this is the frequency we get from the pitch tracker
        float freq_is = tuner->freq;
        // Now we translate reference_pitch from LA to DO
        // to get the reference pitch of the first Note in Octave 4
        // La hvae a ratio of 5/3 = 1.666666667
        // so divide the reference_pitch by 1.666666667 will
        // give us the reference pitch for DO in Octave 4
        float ref_c = tuner->reference_pitch / noteratio[6];
        // now check in which Octave we are with the tracked frequency
        // and set the Frequency Octave divider
        // ref_c is now the frequency of the first note in Octave,
        // but we wont to check if the frequency is below the last Note in Octave
        // so, for example if freq_is is below ref_c we are in octave 3
        // if freq_is is below ref_c/2 we are in octave 2, etc.
    if (freq_is < (ref_c/8.0)-5.1 && freq_is >0.0) {
        indicate_oc = 0; // standart 27,5hz == 6,25%
        multiply = 16;
    } else if (freq_is < (ref_c/4.0)-5.1) {
        indicate_oc = 1; // standart 55hz == 12,5%
        multiply = 8;
    } else if (freq_is < (ref_c/2.0)-5.1) {
        indicate_oc = 2; // standart 110hz == 25&
        multiply = 4;
    } else if (freq_is < (ref_c)-5.1) {
        indicate_oc = 3; // standart 220hz == 50%
        multiply = 2;
    } else if (freq_is < (ref_c*2.0)-5.1) {
        indicate_oc = 4; // standart 440hz == 100%
        multiply = 1;
    } else if (freq_is < (ref_c*4.0)-5.1) {
        indicate_oc = 5; // standart 880hz == 200%
        multiply = 0.5;
    } else if (freq_is < (ref_c*8.0)-5.1) {
        indicate_oc = 6; // standart 1760hz == 400%
        multiply = 0.25;
    } else if (freq_is < (ref_c*16.0)-5.1) {
        indicate_oc = 7; // standart 3520hz == 800%
        multiply = 0.125;
    } else {
        indicate_oc = 8;
        multiply = 0.0625;
    }
    // we divide ref_c (refernce frequency of DO in Octave 4)
    // with the multiply var, to get the frequency of DO in the Octave we are in.
    // then we devide the fetched frequency by the frequency of this (DO in this octave)
    // we get the ratio of the fetched frequency to the first Note in octave
    percent = (freq_is/(ref_c/multiply)) ;
    //fprintf(stderr, " percent == %f freq = %f ref_c = %f indicate_oc = %i \n", percent, freq_is, ref_c, indicate_oc);

    for (int n=0 ; (n=numberofnotes) ; ++n )
         { float ratiodiff = ((noteratio[n]+noteratio[n+1])/2); 
                 if (percent < ratiodiff) {
                     display_note = n;
                     scale = ((percent-noteratio[n]))/2.0;
                     break;
                 }
         }
        // display note
        cairo_set_source_rgba(cr, fabsf(scale)*3.0, 1-fabsf(scale)*3.0, 0.2,1-fabsf(scale)*2);
        cairo_set_font_size(cr, 18.0);
        cairo_move_to(cr,x0+50 -9 , y0+30 +9 );
        cairo_show_text(cr, diatonic_note[display_note]);
        cairo_set_font_size(cr, 8.0);
        cairo_move_to(cr,x0+54  , y0+30 +16 );
        cairo_show_text(cr, octave[indicate_oc]);
    }

    // display frequency
    char s[10];
    snprintf(s, sizeof(s), "%.1f Hz", tuner->freq);
    cairo_set_source_rgb (cr, 0.5, 0.5, 0.1);
    cairo_set_font_size (cr, 7.5);
    cairo_text_extents_t ex;
    cairo_text_extents(cr, s, &ex);
    cairo_move_to (cr, x0+98-ex.width, y0+58);
    cairo_show_text(cr, s);
    // display cent
    if(scale>-0.4) {
        if(scale>0.004) {
            // here we translate the scale factor to cents and display them
            cents = static_cast<int>((floorf(scale * 10000) / 50));
            snprintf(s, sizeof(s), "+%i", cents);
            cairo_set_source_rgb (cr, 0.05, 0.5+0.022* abs(cents), 0.1);
            gx_tuner_triangle(cr, x0+80, y0+40, -15, 10);
            cairo_set_source_rgb (cr, 0.5+ 0.022* abs(cents), 0.35, 0.1);
            gx_tuner_triangle(cr, x0+20, y0+40, 15, 10);
            gx_tuner_strobe(cr, x0, y0, static_cast<double>(cents));
        } else if(scale<-0.004) {
            cents = static_cast<int>((ceil(scale * 10000) / 50));
            snprintf(s, sizeof(s), "%i", cents);
            cairo_set_source_rgb (cr, 0.05, 0.5+0.022* abs(cents), 0.1);
            gx_tuner_triangle(cr, x0+20, y0+40, 15, 10);
            cairo_set_source_rgb (cr, 0.5+ 0.022* abs(cents), 0.35, 0.1);
            gx_tuner_triangle(cr, x0+80, y0+40, -15, 10);
            gx_tuner_strobe(cr, x0, y0, static_cast<double>(cents));
        } else {
            cents = static_cast<int>((ceil(scale * 10000) / 50));
            mini_cents = (scale * 10000) / 50;
            if (mini_cents<0)
                snprintf(s, sizeof(s), "%.2f", mini_cents);
            else
                snprintf(s, sizeof(s), "+%.2f", mini_cents);
            cairo_set_source_rgb (cr, 0.05* abs(cents), 0.5, 0.1);
            gx_tuner_triangle(cr, x0+80, y0+40, -15, 10);
            gx_tuner_triangle(cr, x0+20, y0+40, 15, 10);
            gx_tuner_strobe(cr, x0, y0, mini_cents);
        }
    } else {
        cents = 100;
        snprintf(s, sizeof(s), "+ - cent");
    }   
    cairo_set_source_rgb (cr, 0.5, 0.5, 0.1);
    cairo_set_font_size (cr, 6.0);
    cairo_text_extents(cr, s, &ex);
    cairo_move_to (cr, x0+28-ex.width, y0+58);
    cairo_show_text(cr, s);

    double ux=2., uy=2.;
    cairo_device_to_user_distance (cr, &ux, &uy);
    if (ux < uy)
        ux = uy;
    cairo_set_line_width (cr, ux + grow);

    // indicator (line)
    cairo_move_to(cr,x0+50, y0+rect_height+5);
    cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
    cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
    cairo_set_dash (cr, dash_ind, sizeof(dash_ind)/sizeof(dash_ind[0]), 1);
    cairo_line_to(cr, (log_scale(cents, scale)*2*rect_width)+x0+50, y0+(scale*scale*30)+2);
    cairo_set_source_rgb(cr,  0.5, 0.1, 0.1);
    cairo_stroke(cr);   

    g_free (allocation);
    return FALSE;
}


btw: you where right about the 5.1Hz difference. Lowering it solves the problem.
User avatar
Broomy
 
Posts: 194
Joined: Thu Apr 24, 2014 7:53 am

Re: Indian Scale tuner

Postby brummer10 » Fri Nov 17, 2017 3:48 am

Code: Select all
   // copy the following block and edit it to your needs to add a new tuning mode
    static gboolean gtk_tuner_expose_diatonic(GtkWidget *widget, cairo_t *cr) {
        // Note names for display
        static const char* diatonic_note[] = {"Do","Re","Mi","Fa","Sol","La ","Ti"};
        float noteratio[] = {1/1, 9/8, 5/4, 3/2, 4/3, 5/3, 15/8, 2/1};
        int numberofnotes = (sizeof(noteratio) - 1) ;

float noteratio[] = {1/1, 9/8, 5/4, 3/2, 4/3, 5/3, 15/8, 2/1};

here you must use at least one float in the calculation, otherwise the result will expressed as integer and becomes zero , so this become:
float noteratio[] = {1/1.0, 9/8.0, 5/4.0, 3/2.0, 4/3.0, 5/3.0, 15/8.0, 2/1.0};

int numberofnotes = (sizeof(noteratio) - 1) ;

tor get the size of the array you must use the following expression:

int numberofnotes = (sizeof(noteratio) /sizeof(noteratio[0]));

why do you subtract 1?

Code: Select all
       
         for (int n=0 ; (n=numberofnotes) ; ++n )
             { float ratiodiff = ((noteratio[n]+noteratio[n+1])/2);
                     if (percent < ratiodiff) {
                         display_note = n;
                         scale = ((percent-noteratio[n]))/2.0;
                         break;
                     }
             }


for (int n=0 ; (n=numberofnotes) ; ++n )

the second statement here just set n = numberofnotes.
A single = just set the value for variable, a double == compare to values.
It should be smaller as
n <= numberofnotes
or not equal
n != numberofnotes

otherwise it will run endless, and overflow the array size.

for debugging I mostly use stances like this to check were a value maybe wrong:
fprintf(stderr, " value of numberofnotes is %i", numberofnotes)
fprintf(stderr, " value of noteratio is %f", noteratio)
fprintf(stderr, " selected diatonic_note is %s", diatonic_note[i])

regards
hermann
User avatar
brummer10
Site Admin
 
Posts: 782
Joined: Thu Mar 26, 2009 6:57 pm

Re: Indian Scale tuner

Postby Broomy » Fri Nov 17, 2017 8:02 am

Thanks for being such a patient teacher.

brummer10 wrote:why do you subtract 1?

Array of ratios has one more then the number of notes (2/1 ratio).

I will give an update soon!

Hans
User avatar
Broomy
 
Posts: 194
Joined: Thu Apr 24, 2014 7:53 am

Just Intonation Tuner

Postby Broomy » Fri Nov 17, 2017 8:27 pm

Made a commit. As far as I can tell right now, all the presets are working. I'll will check more thoroughly this weekend. All presets use the same code structure.
It saved about 300 lines, so that's a nice improvement (the 65note preset required a lot of lines).

Another thought occurred: The only difference between the presets are the two arrays containing the note names and ratios, all the other code (except one line) is the same. Would it be possible to organize it as follows?

Data {
Arrays of preset one
Arrays of preset two
Arrays of preset three
Arrays of preset four
etc }

Generic code {
--> check which preset is chosen
--> load the appropriate arrays
--> Let's get those notes in tune...
--> Do this until the preset is changed
}

If that's possible then adding a new preset will be pretty straight forward.

Hans
User avatar
Broomy
 
Posts: 194
Joined: Thu Apr 24, 2014 7:53 am

Re: Indian Scale tuner

Postby brummer10 » Sat Nov 18, 2017 6:54 am

Yes, we can define the notes and ratios as global static members, on the beginning of the file (line 82 or so)

example:
Code: Select all
static const char* diatonic_note[] = {"Do","Re","Mi","Fa","Sol","La ","Ti"};
static float diatonic_ratio[] = {1/1.0, 9/8.0, 5/4.0, 4/3.0, 3/2.0, 5/3.0, 15/8.0, 2/1.0};

etc.

and we define 2 new members in gxtuner.h
Code: Select all
struct _GxTuner
{
....
const char **note;
float * ratio;
}


in gxtuner.cpp we could assign this pointers to the wonted notes and ratios. First we set them in
static void gx_tuner_init (GxTuner *tuner) {
to the wonted default:

tuner->note = default_note;
tuner->ratio = default_ratio;

then in
void gx_tuner_set_mode(GxTuner *tuner, int mode) {

we could assign them to what is chosen:
Code: Select all
    switch(tuner->mode) {
    case  0:
        tuner->note = default_note;
        tuner->ratio = default_ratio;
        break;
    case 1:
        tuner->note = diatonic_note;
        tuner->ratio = diatonic_ratio;
        break;
    case 2:
       . . .
     default:
        tuner->note = default_note;
        tuner->ratio = default_ratio;
        break;
    }



Be aware that we enter now multi threading, that means that note and ratio could change even in the middle of a expose call, that means you must control that the chosen note is inside the note array. So, to say, if you switch to a smaller note set, and in the expose call already a higher note is detected, the program crash. You must integrate a control that the selected note is smaller then the array size.

Oh, I forgot to mention, nice maths you come up with. :)
User avatar
brummer10
Site Admin
 
Posts: 782
Joined: Thu Mar 26, 2009 6:57 pm

PreviousNext

Return to Suggestion Box

Who is online

Users browsing this forum: No registered users and 1 guest

cron