Old 07-01-2020, 05:59 PM   #1
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default Overlaying guitar chord grids

This preset for the video processor overlays a guitar chord grid on the video, good for instructional guitar videos.

UPDATE: This version is outdated. (But it doesn't use unicode for the finger-spots, which might be useful to some.) See post #21 for a much better version. See post #37 for a version with a knob that sets the chord root and chord type. See also posts #33 and #35.

Code:
// overlay guitar chord grid
// July 3 2020 by TallKite Software
// to omit the chord name, set it to "", to center it, add trailing spaces
// frets can be 0 for open or x for unused. numStrings = length of #frets
// barre strings have 3 numbers: start string, end string and fret
// if there is no 3rd number, the fret is assumed to be 1
#chord = "Ab7  ";
#frets = "x3x2xx";              // relative to the 1st fret shown
#barre = "64";
#barre2 = "";

//@param1:xpos 'x position' 0.5 0 1 0.5 0.01
//@param2:ypos 'y position' 0.5 0 1 0.5 0.01
//@param4:numFrets 'number of frets' 5 4 8 6 1
//@param6:startFret 'starting fret number' 1 1 21 11 1
//@param8:fontSize 'font size' 60 20 120 70 5
//@param9:border 'border' 20 5 45 30 1
//@param10:gap 'gap under name' 20 10 30 20 1
//@param12:colwid 'string spacing' 40 20 60 40 2
//@param13:rowht 'fret spacing' 40 20 60 40 2
//@param14:LT 'line thickness' 5 1 9 5 1
//@param15:spotSize 'finger-spot size' 0.8 0.5 1 0.75 0.02
//@param17:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Black";                   // for the finger-spot
sharp = "♯"; flat  = "♭";
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, 1);                              // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, 1);                              // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                     //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                    // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
i = 0; xpos2 = xpos;                                //========== STRINGS =======
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48 - 0.5;        // 0.5 to go between frets
  gfx_setfont (spotSize * rowht, font3);
  gfx_str_measure ("O", spotW, spotH);              // kluge for spots: draw a fat "O"
  gfx_str_draw ("O", xpos2 - spotW/2, ypos + rowht * fret - spotH/2);
  fret > 0 ? (                                      // unless it's an open string,
    w2 = spotW * 0.6; h2 = spotH * 0.35;            // plug the hole with a rectangle
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink plugs
    gfx_fillRect (xpos2 - w2/2, ypos + rowht * fret - h2/2, w2, h2);
    // gfx_set (0, 0, 0, 1);                        // for debugging, back to black
  );
  xpos2 += colwid;
  i += 1;
);

strlen (#barre) > 0 ? (                             //======== 1ST BARRE =========
  string1 = str_getchar (#barre, 0) - 48;
  string2 = str_getchar (#barre, 1) - 48;
  string1 < string2 ? (
    i = string1; string1 = string2; string2 = i);
  strlen (#barre) == 2 ? fret = 1
  : fret = str_getchar (#barre, 2) - 48;
  xpos2 = xpos + (numStrings - string1) * colwid;
  ypos2 = ypos + rowht * (fret - 0.5);
  barreLen = colwid * abs (string2 - string1);
  gfx_str_draw ("O", xpos2 - spotW/2, ypos2 - spotH/2);
  gfx_str_draw ("O", xpos2 - spotW/2 + barreLen, ypos2 - spotH/2);
  gfx_fillRect (xpos2 - colwid/5, ypos2 - spotH/4, barreLen + colwid/2.5, spotH/2);
);

strlen (#barre2) > 0 ? (                             //======== 2ND BARRE =========
  string1 = str_getchar (#barre2, 0) - 48;
  string2 = str_getchar (#barre2, 1) - 48;
  string1 < string2 ? (
    i = string1; string1 = string2; string2 = i);
  strlen (#barre2) == 2 ? fret = 1
  : fret = str_getchar (#barre2, 2) - 48;
  xpos2 = xpos + (numStrings - string1) * colwid;
  ypos2 = ypos + rowht * (fret - 0.5);
  barreLen = colwid * abs (string2 - string1);
  gfx_str_draw ("O", xpos2 - spotW/2, ypos2 - spotH/2);
  gfx_str_draw ("O", xpos2 - spotW/2 + barreLen, ypos2 - spotH/2);
  gfx_fillRect (xpos2 - colwid/5, ypos2 - spotH/4, barreLen + colwid/2.5, spotH/2);
);
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html

Last edited by Kite; 07-11-2020 at 10:48 PM.
Kite is offline   Reply With Quote
Old 07-01-2020, 06:00 PM   #2
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Here's a microtonal version with a custom font for ^ and v. See post #22 for a better version.

Code:
// overlay microtonal guitar chord grid
// July 1 2020 by TallKite Software
// to omit the chord name, set it to "", to center it, add trailing spaces
// frets can be 0 for open or x for unused. numStrings = length of #frets
// barre strings have 3 numbers: start string, end string and fret
// if there is no 3rd number, the fret is assumed to be 1
#chord = "Abv7";
#frets = "4x315x";              // relative to the 1st fret shown
#barre = "";
#barre2 = "";

//@param1:xpos 'x position' 0.5 0 1 0.5 0.01
//@param2:ypos 'y position' 0.5 0 1 0.5 0.01
//@param4:numFrets 'number of frets' 5 4 8 6 1
//@param5:dotFret 'fret with dot' 4 0 5 2.5 1
//@param6:dotNum 'dot number' 1 1 9 5 1
//@param8:fontSize 'font size' 60 20 120 70 5
//@param9:border 'border' 20 5 45 30 1
//@param10:gap 'gap under name' 20 10 30 20 1
//@param12:colwid 'string spacing' 40 20 60 40 2
//@param13:rowht 'fret spacing' 40 20 60 40 2
//@param14:LT 'line thickness' 5 1 9 5 1
//@param15:spotSize 'finger-spot size' 0.8 0.5 1 0.75 0.02
//@param17:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs
font4 = "Arial Black";                   // for the fingering dot
sharp = "♯"; flat  = "♭";
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
  dotNum == 1 ? #sideNum = "1st"
: dotNum == 2 ? #sideNum = "2nd"
: dotNum == 3 ? #sideNum = "3rd"
: (#sideNum = "Nth"; str_setchar (#sideNum, 0, dotNum + 48));
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
dotFret > 0 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, 1);                              // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, 1);                              // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    strcmp (#s, "^") == 0 ? (f = font3);
    strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

dotFret > 0 ? (                                     //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + (dotFret - 0.5) * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; dotFret > 0 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
dotFret == 0 || (dotFret == 4 && dotNum == 1) ?     // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 1.5*LT, (numStrings - 1) * colwid + LT, 1.5*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
i = 0; xpos2 = xpos;                                //========== STRINGS =======
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48 - 0.5;        // 0.5 to go between frets
  gfx_setfont (spotSize * rowht, font4);    
  gfx_str_measure ("O", spotW, spotH);              // kluge for spots: draw a fat "O"
  gfx_str_draw ("O", xpos2 - spotW/2, ypos + rowht * fret - spotH/2);
  fret > 0 ? (                                      // unless it's an open string,
    w2 = spotW * 0.6; h2 = spotH * 0.35;            // plug the hole with a srectangle
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink plugs
    gfx_fillRect (xpos2 - w2/2, ypos + rowht * fret - h2/2, w2, h2);
    // gfx_set (0, 0, 0, 1);                        // for debugging, back to black
  );
  xpos2 += colwid;
  i += 1;
);

strlen (#barre) > 0 ? (                             //======== 1ST BARRE =========
  string1 = str_getchar (#barre, 0) - 48;
  string2 = str_getchar (#barre, 1) - 48;
  string1 < string2 ? (
    i = string1; string1 = string2; string2 = i);
  strlen (#barre) == 2 ? fret = 1
  : fret = str_getchar (#barre, 2) - 48;
  xpos2 = xpos + (numStrings - string1) * colwid;
  ypos2 = ypos + rowht * (fret - 0.5);
  barreLen = colwid * abs (string2 - string1);
  gfx_str_draw ("O", xpos2 - spotW/2, ypos2 - spotH/2);
  gfx_str_draw ("O", xpos2 - spotW/2 + barreLen, ypos2 - spotH/2);
  gfx_fillRect (xpos2 - colwid/5, ypos2 - spotH/4, barreLen + colwid/2.5, spotH/2);
);

strlen (#barre2) > 0 ? (                             //======== 2ND BARRE =========
  string1 = str_getchar (#barre2, 0) - 48;
  string2 = str_getchar (#barre2, 1) - 48;
  string1 < string2 ? (
    i = string1; string1 = string2; string2 = i);
  strlen (#barre2) == 2 ? fret = 1
  : fret = str_getchar (#barre2, 2) - 48;
  xpos2 = xpos + (numStrings - string1) * colwid;
  ypos2 = ypos + rowht * (fret - 0.5);
  barreLen = colwid * abs (string2 - string1);
  gfx_str_draw ("O", xpos2 - spotW/2, ypos2 - spotH/2);
  gfx_str_draw ("O", xpos2 - spotW/2 + barreLen, ypos2 - spotH/2);
  gfx_fillRect (xpos2 - colwid/5, ypos2 - spotH/4, barreLen + colwid/2.5, spotH/2);
);
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html

Last edited by Kite; 07-11-2020 at 10:49 PM.
Kite is offline   Reply With Quote
Old 07-01-2020, 08:19 PM   #3
EpicSounds
Human being with feelings
 
EpicSounds's Avatar
 
Join Date: Jul 2009
Posts: 5,958
Default

holy crap that must have been a lot of work! looks great actually
__________________
REAPER Video Tutorials, Tips & Tricks and more at The REAPER Blog
EpicSounds is offline   Reply With Quote
Old 07-01-2020, 09:55 PM   #4
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Quote:
Originally Posted by EpicSounds View Post
holy crap that must have been a lot of work! looks great actually
Thank you!
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-02-2020, 02:47 AM   #5
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Amazing, Kite. Its always impressive what people get out of the video processor. This is a very cool addition. People could even put chords and other aspects into variables to just change the chords or automate them as a parameter like their need.

Many thanks.
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-02-2020, 02:52 AM   #6
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 271
Default

@Kite : I love you man
daeavelwyn is offline   Reply With Quote
Old 07-02-2020, 10:51 AM   #7
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Quote:
Originally Posted by daeavelwyn View Post
@Kite : I love you man
Enjoy!

Quote:
Originally Posted by Eliseat View Post
Amazing, Kite. Its always impressive what people get out of the video processor. This is a very cool addition. People could even put chords and other aspects into variables to just change the chords or automate them as a parameter like their need.

Many thanks.
You're welcome! But how would you automate a text string?
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-02-2020, 03:49 PM   #8
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Hm, you ask me questions.

I saw something like that in Amalgamas Text overlay preset. He put the text strings of listed fonts in numbered variables which belong to a parameter variable. I know, if I describe it, it sounds really stupid.

But here is the example code:
Code:
// Serif fonts
sans == 1 ? (
  font == 1 ? font="Gabriola";
  font == 2 ? font="Palatino Linotype";
  font == 3 ? font="Comic Sans MS";
  font == 4 ? font="Aquire";
  font == 5 ? font="Times";
  font == 6 ? font="Cambria";
  font == 7 ? font="Georgia";
  font == 8 ? font="Courier";
) : (
In the end you get a parameter "font", which lets you scroll thru the numbers 1-8 to change the text strings of font. If I'm not misinterpreting it, it could offer a way to load a parameter variable "Chord" with of chords ... I don't know.

Maybe this helps or its really stupid.

Greetings
Eli
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-02-2020, 04:04 PM   #9
EpicSounds
Human being with feelings
 
EpicSounds's Avatar
 
Join Date: Jul 2009
Posts: 5,958
Default

can confirm that works, I'm using it in my text generators.

You can also use item name as the string. It would be pretty difficult to actually get the chord fingering automatically from the name though.
__________________
REAPER Video Tutorials, Tips & Tricks and more at The REAPER Blog
EpicSounds is offline   Reply With Quote
Old 07-02-2020, 07:06 PM   #10
lachinhan
Human being with feelings
 
lachinhan's Avatar
 
Join Date: Nov 2014
Location: Can Tho - Viet Nam
Posts: 171
Default

So Great! Thank you.
__________________
NK Recording Studio
Email: lachinhan@gmail.com or admin@thuamninhkieu.com
Website:nkpro.top and ntmusicpro.com
lachinhan is offline   Reply With Quote
Old 07-02-2020, 07:57 PM   #11
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Quote:
Originally Posted by Eliseat View Post
In the end you get a parameter "font", which lets you scroll thru the numbers 1-8 to change the text strings of font. If I'm not misinterpreting it, it could offer a way to load a parameter variable "Chord" with of chords ... I don't know.
Got it. The parameter lets you choose between a number of built-in options. So the code could have a parameter "root", with 0 = C, 1 = G, 2 = D, etc. All the way up to say 8 for G#, and all the way back to say -5 for Db. Then you could have another parameter "chord type", 1 = major, 2 = minor, 3 = dom7, etc.

Interesting idea, but I'll let someone else add that feature.


Quote:
Originally Posted by EpicSounds View Post
You can also use item name as the string. It would be pretty difficult to actually get the chord fingering automatically from the name though.
That's actually in there, but commented out. So if anyone wants to use the item name, just uncomment this line:

Code:
strlen (#chord) == 0 ? input_get_name (-1, #chord);
I commented it out so that you could have unnamed chords.


Quote:
Originally Posted by lachinhan View Post
So Great! Thank you.
You're welcome! Glad you like it!
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-03-2020, 11:40 AM   #12
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Quote:
Originally Posted by Kite View Post
Got it. The parameter lets you choose between a number of built-in options. So the code could have a parameter "root", with 0 = C, 1 = G, 2 = D, etc. All the way up to say 8 for G#, and all the way back to say -5 for Db. Then you could have another parameter "chord type", 1 = major, 2 = minor, 3 = dom7, etc.

Interesting idea, but I'll let someone else add that feature.
Hi Kite,
would it be possible to even use a function to force the frets and barres for the chosen chord? Like if chord == "E minor" then frets == "022000" etc.?

So if I understand it right the chord variable would need two components (root and chtype) and this chord variable then could force the actual fret? Seems logical. And maybe doable for me. I will think about it.

In a simple plan:


root == 1 ? root="C";
root == 2 ? root="C#";
root == 3 ? root="D";
etc.

chtype == 1 ? chtype="major";
chtype == 2 ? chtype="minor";
chtype == 3 ? chtype="dom7";
etc.

chord == (root.chtype)
if chord == "E minor" -> frets == "022000"
etc.



Greetings
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-03-2020, 02:13 PM   #13
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Yes, this is totally doable. Go for it!

Quote:
Originally Posted by Eliseat View Post
root == 1 ? root="C";
root == 2 ? root="C#";
root == 3 ? root="D";
etc.
Sometimes you want to call a chord C# and sometimes you want to call it Db, so I would set it up like this:

Code:
root == -6 ? root="Gb";
root == -5 ? root="Db";
root == -4 ? root="Ab";
root == -3 ? root="Eb";
root == -2 ? root="Bb";
root == -1 ? root="F";
root == 0 ? root="C";
root == 1 ? root="G";
root == 2 ? root="D";
root == 3 ? root="A";
root == 4 ? root="E";
root == 5 ? root="B";
root == 6 ? root="F#";
root == 7 ? root="C#";
root == 8 ? root="G#";
root == 9 ? root="D#";
This gives the user control over how the chord is named. The numbers run negative to positive to provide a good mnemonic for which note has which number. D is +2 because the key of D major has 2 sharps, Eb is -3 because that key has 3 fats, etc.

BTW I recently edited the OP to fix a bug with the starting fret number.
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-03-2020, 07:48 PM   #14
WyattRice
Human being with feelings
 
WyattRice's Avatar
 
Join Date: Sep 2009
Location: Virginia
Posts: 1,988
Default

Wonderful!
Thanks for sharing this.

Is there a way you could add rotate so that the nut is on the left?
Just curious.
Anyway, Many thanks!

Wyatt
WyattRice is offline   Reply With Quote
Old 07-04-2020, 12:53 AM   #15
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Quote:
Originally Posted by WyattRice View Post
Is there a way you could add rotate so that the nut is on the left?
Could be done. But of course the nut-on-top format is much better for lefties. Anyway, sorry, I don't want to take that on. Perhaps someone else here could tinker with the code.
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-04-2020, 07:53 AM   #16
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Can someone tell me how to merge two or more variables in EEL? Like in name = "John" lname = "Wick" fullname = name.lname?

In Lua its done with a dot if I remember right. But how is this done in EEL?
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-04-2020, 02:08 PM   #17
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

#chord = strcat (#root, #chtype);
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-04-2020, 02:44 PM   #18
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Got it to work. Here is kind of a prototype only with major chords:

Code:
// overlay guitar chord grid
// to omit the chord name, set it to "", to center it, add trailing spaces
// frets can be 0 for open or x for unused. numStrings = length of #frets
// barre strings have 3 numbers: start string, end string and fret
// if there is no 3rd number, the fret is assumed to be 1

root == 0 ? root_str="C";
root == 1 ? root_str="C#";
root == 2 ? root_str="D";
root == 3 ? root_str="D#";
root == 4 ? root_str="E";
root == 5 ? root_str="F";
root == 6 ? root_str="F#";
root == 7 ? root_str="G";
root == 8 ? root_str="G#";
root == 9 ? root_str="A";
root == 10 ? root_str="A#";
root == 11 ? root_str="B";

chtype == 1 ? chtype_str="maj";
chtype == 2 ? chtype_str="min";
chtype == 3 ? chtype_str="7";

#chord = sprintf(#, "%s %s", root_str, chtype_str);

root == 0 && chtype == 1 ? (#frets = "x32010";#barre = "")  :
root == 1 && chtype == 1 ? (#frets = "x06660"; #barre = "514")  :
root == 2 && chtype == 1 ? (#frets = "xx0232"; #barre = "")  :
root == 3 && chtype == 1 ? (#frets = "x65040"; #barre = "313")  :
root == 4 && chtype == 1 ? (#frets = "022100"; #barre = "")  :
root == 5 && chtype == 1 ? (#frets = "033200"; #barre = "611")  :
root == 6 && chtype == 1 ? (#frets = "044300"; #barre = "612")  :
root == 7 && chtype == 1 ? (#frets = "320003"; #barre = "")  :
root == 8 && chtype == 1 ? (#frets = "066500"; #barre = "614")  :
root == 9 && chtype == 1 ? (#frets = "x02220"; #barre = "")  :
root == 10 && chtype == 1 ? (#frets = "x03330"; #barre = "511")  :
root == 11 && chtype == 1 ? (#frets = "x04440"; #barre = "512")  :

(#frets = "000000"; #barre = "";) ;

//#chord = "Ab7  "; 
//#frets = "x3x2xx";              // relative to the 1st fret shown
//#barre = "64";
#barre2 = "";

//@param1:root 'Root' 0 0 11 1 1
//@param2:chtype 'Chord type' 1 1 3 1 1
//@param3:xpos 'x position' 0.5 0 1 0.5 0.01
//@param4:ypos 'y position' 0.5 0 1 0.5 0.01
//@param5:numFrets 'number of frets' 5 4 8 6 1
//@param6:startFret 'starting fret number' 1 1 21 11 1
//@param8:fontSize 'font size' 60 20 120 70 5
//@param9:border 'border' 20 5 45 30 1
//@param10:gap 'gap under name' 20 10 30 20 1
//@param12:colwid 'string spacing' 40 20 60 40 2
//@param13:rowht 'fret spacing' 40 20 60 40 2
//@param14:LT 'line thickness' 5 1 9 5 1
//@param15:spotSize 'finger-spot size' 0.8 0.5 1 0.75 0.02
//@param17:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Black";                   // for the finger-spot
sharp = "♯"; flat  = "♭";
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, 1);                              // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, 1);                              // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                     //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                    // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
i = 0; xpos2 = xpos;                                //========== STRINGS =======
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48 - 0.5;        // 0.5 to go between frets
  gfx_setfont (spotSize * rowht, font3);
  gfx_str_measure ("O", spotW, spotH);              // kluge for spots: draw a fat "O"
  gfx_str_draw ("O", xpos2 - spotW/2, ypos + rowht * fret - spotH/2);
  fret > 0 ? (                                      // unless it's an open string,
    w2 = spotW * 0.6; h2 = spotH * 0.35;            // plug the hole with a srectangle
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink plugs
    gfx_fillRect (xpos2 - w2/2, ypos + rowht * fret - h2/2, w2, h2);
    // gfx_set (0, 0, 0, 1);                        // for debugging, back to black
  );
  xpos2 += colwid;
  i += 1;
);

strlen (#barre) > 0 ? (                             //======== 1ST BARRE =========
  string1 = str_getchar (#barre, 0) - 48;
  string2 = str_getchar (#barre, 1) - 48;
  string1 < string2 ? (
    i = string1; string1 = string2; string2 = i);
  strlen (#barre) == 2 ? fret = 1
  : fret = str_getchar (#barre, 2) - 48;
  xpos2 = xpos + (numStrings - string1) * colwid;
  ypos2 = ypos + rowht * (fret - 0.5);
  barreLen = colwid * abs (string2 - string1);
  gfx_str_draw ("O", xpos2 - spotW/2, ypos2 - spotH/2);
  gfx_str_draw ("O", xpos2 - spotW/2 + barreLen, ypos2 - spotH/2);
  gfx_fillRect (xpos2 - colwid/5, ypos2 - spotH/4, barreLen + colwid/2.5, spotH/2);
);

strlen (#barre2) > 0 ? (                             //======== 2ND BARRE =========
  string1 = str_getchar (#barre2, 0) - 48;
  string2 = str_getchar (#barre2, 1) - 48;
  string1 < string2 ? (
    i = string1; string1 = string2; string2 = i);
  strlen (#barre2) == 2 ? fret = 1
  : fret = str_getchar (#barre2, 2) - 48;
  xpos2 = xpos + (numStrings - string1) * colwid;
  ypos2 = ypos + rowht * (fret - 0.5);
  barreLen = colwid * abs (string2 - string1);
  gfx_str_draw ("O", xpos2 - spotW/2, ypos2 - spotH/2);
  gfx_str_draw ("O", xpos2 - spotW/2 + barreLen, ypos2 - spotH/2);
  gfx_fillRect (xpos2 - colwid/5, ypos2 - spotH/4, barreLen + colwid/2.5, spotH/2);
);
I have no idea if this is the proper way, but it works like expected and imagined above in the thread. Many thanks to the helpers, Kite and Fabian!

I will try to increase the available chords and types soon.
greetings
Eli
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-04-2020, 07:43 PM   #19
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Oh no, I'm modding the code to use unicode for the finger-spots, plus other improvements. But here you are already modding the code in another direction. What to do?

Related question, when I upload a new version, should I edit the OP or make a new post? I'm thinking the latter, so you don't lose what you started from.
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-04-2020, 09:19 PM   #20
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

That's no problem. Post your updates and I will adapt my additional code. Or you take my approach and use it in your newer version. The goal was to show, if its possible to make it automatable. And that's the case.

__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-04-2020, 11:17 PM   #21
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

New version of the effect

CHANGELOG:
7-08-2020 added optional X above unplayed strings
7-11-2020 added optional fingerings
7-11-2020 small bug fix for fret number placement when there's no chord name

Code:
// overlay chord grid
// July 11 2020 by TallKite Software
// to omit the chord name, set it to "", to center it, add trailing spaces
// numStrings = length of #frets. 0 = open, x or space = unused (space = no X shown)
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string
#chord = "Ab7    ";
#frets = " 3 2  ";              // relative to the 1st fret shown
#barre = "611";
#barre2 = "";
#barre3 = "";
#fingering = "131211";          // use space for unplayed, use T or 0 for thumb

//@param1:xpos 'x position' 0.5 0 1 0.5 0.01
//@param2:ypos 'y position' 0.5 0 1 0.5 0.01
//@param3:numFrets 'number of frets' 5 4 8 6 1
//@param4:startFret 'starting fret' 1 1 21 11 1

//@param6:fontSize 'font size' 60 20 120 70 5
//@param7:border 'border' 20 5 45 30 1
//@param8:gap 'gap under name' 20 10 30 20 1

//@param10:colwid 'string spacing' 40 20 60 40 2
//@param11:rowht 'fret spacing' 40 20 60 40 2
//@param12:LT 'line thickness' 5 1 9 5 1
//@param13:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02
//@param14:fingerSize 'fingering size' 1.2 0.7 1.7 1.2 0.05

//@param16:opacity 'opacity' 1 0 1 0.5 0.01
//@param17:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "⬤"; hollowSpot = "⭕"; ex = "✖";  // unicode 2B24, 2B55 and 2716

input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);

//strlen (#chord) == 0 ? input_get_name (-1, #chord);   // uncomment to use item's name
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
spotSize *= rowht;                                 // convert from percentage to pixels
width = (numStrings - 1) * colwid + 2 * border + spotSize;    // room for spots to stick out
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
strlen (#fingering) > 0 ? height += fingerSize*colwid;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, opacity);                        // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    //strcmp (#s, "^") == 0 ? (f = font3);         // (microtonal notation)
    //strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                   //====== FRET NUMBER ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + 0.5 * rowht - sideH/2;
  strlen (#chord) > 0 ? ypos2 += defH + gap;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border + spotSize/2;                        //========== GRID ===========
startFret > 1 ? xpos += sideW + border;
ypos += border; strlen (#chord) > 0 ? ypos += defH + gap;
startFret == 1 ?                                         // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize, font1);                      //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.5) * rowht);
  fret = str_getchar (#frets, i) - 48;              // zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
loop (3,                                            // kluge
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink
    gfx_fillRect (xpos2, ypos2 - spotSize/2, barreLen, spotSize);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
  #barre = #barre2; #barre2 = #barre3;    // kluge to avoid learning about functions!
);

strlen (#fingering) > 0 ? (                         // ======== FINGERING =======
  gfx_setfont (fingerSize*colwid, font1);
  xpos2 = xpos;                                     // go to the first guitar string
  ypos += rowht * (numFrets + 0.5);                 // go to the bottom of the string
  ypos += 0.1 * rowht;                              // add the gap above fingerings
  i = 0; 
  loop (numStrings,
    strcpy_substr (#s, #fingering, i, 1); 
    gfx_str_measure (#s, fingerW, fingerH);
    gfx_str_draw (#s, xpos2 - fingerW/2, ypos);
    xpos2 += colwid;
    i += 1;
  );
);
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html

Last edited by Kite; 07-11-2020 at 11:15 PM.
Kite is offline   Reply With Quote
Old 07-04-2020, 11:18 PM   #22
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

Microtonal version

CHANGELOG:
7-08-2020 added optional X above unplayed strings
7-11-2020 added optional fingerings
7-11-2020 small bug fix for fret number placement when there's no chord name

Code:
// overlay chord grid
// July 11 2020 by TallKite Software
// to omit the chord name, set it to "", to center it, add trailing spaces
// numStrings = length of #frets. 0 = open, x = unused, space = unused
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string
#chord = "Abv7";
#frets = "4x315x";              // relative to the 1st fret shown
#barre = "";
#barre2 = "";
#barre3 = "";
#fingering = "3 214 ";          // use space for unplayed, use T or 0 for thumb

//@param1:xpos 'x position' 0.5 0 1 0.5 0.01
//@param2:ypos 'y position' 0.5 0 1 0.5 0.01
//@param4:numFrets 'number of frets' 5 4 8 6 1
//@param5:dotFret 'fret with dot' 4 0 5 2.5 1
//@param6:dotNum 'dot number' 1 1 9 5 1
//@param8:fontSize 'font size' 60 20 120 70 5
//@param9:border 'border' 20 5 45 30 1
//@param10:gap 'gap under name' 20 10 30 20 1
//@param12:colwid 'string spacing' 40 20 60 40 2
//@param13:rowht 'fret spacing' 40 20 60 40 2
//@param14:LT 'line thickness' 5 1 9 5 1
//@param15:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02
//@param16:fingerSize 'fingering size' 1.2 0.7 1.7 1.2 0.05
//@param18:opacity 'opacity' 1 0 1 0.5 0.01
//@param19:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "⬤"; hollowSpot = "⭕"; ex = "✖";  // unicode 2B24, 2B55 and 2716

input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);

//strlen (#chord) == 0 ? input_get_name (-1, #chord);  // uncomment to use the item's name
gfx_setfont (fontSize, font1);                     // use default font for now
gfx_str_measure (#chord, defW, defH);              // width & height in default font
  dotNum == 1 ? #sideNum = "1st"
: dotNum == 2 ? #sideNum = "2nd"
: dotNum == 3 ? #sideNum = "3rd"
: (#sideNum = "Nth"; str_setchar (#sideNum, 0, dotNum + 48));
/* alternate sideNum code -- handles 2 digits, but no "-th" suffix
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
*/
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
spotSize *= rowht;                                 // convert from percentage to pixels
width = (numStrings - 1) * colwid + 2 * border + spotSize;  // room for spots to stick out
dotFret > 0 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
strlen (#fingering) > 0 ? height += fingerSize*colwid; // fingering height = fret width
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, opacity);                        // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    strcmp (#s, "^") == 0 ? (f = font3);           // (microtonal notation)
    strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

dotFret > 0 ? (                                     //======= FRET NUMBER ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + (dotFret - 0.5) * rowht - sideH/2;
  strlen (#chord) > 0 ? ypos2 += defH + gap;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border + spotSize/2;                        //======== GRID =========
dotFret > 0 ? xpos += sideW + border; 
ypos += border; strlen (#chord) > 0 ? ypos += defH + gap;
dotFret == 0 || (dotFret == 4 && dotNum == 1) ?     // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize, font1);                      //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.5) * rowht);
  fret = str_getchar (#frets, i) - 48;              // Zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
loop (3,                                            // kluge
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink plugs
    gfx_fillRect (xpos2, ypos2 - spotSize/2, barreLen, spotSize);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
  #barre = #barre2; #barre2 = #barre3;    // kluge to avoid learning about functions!
);

strlen (#fingering) > 0 ? (                         // ======== FINGERING =======
  gfx_setfont (fingerSize*colwid, font1);
  xpos2 = xpos;                                     // go to the first guitar string
  ypos += rowht * (numFrets + 0.5);                 // go to the bottom of the string
  ypos += 0.1 * rowht;                              // add the gap above fingerings
  i = 0; 
  loop (numStrings,
    strcpy_substr (#s, #fingering, i, 1); 
    gfx_str_measure (#s, fingerW, fingerH);
    gfx_str_draw (#s, xpos2 - fingerW/2, ypos);
    xpos2 += colwid;
    i += 1;
  );
);
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html

Last edited by Kite; 07-11-2020 at 11:23 PM.
Kite is offline   Reply With Quote
Old 07-05-2020, 12:55 AM   #23
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Kite, would it be possible to show the x strings also with a x above the bridge? It seems more reasonable for me, because its shown on every chord tabs out there. Maybe I could implement it, if its not to complicated.

Many thanks for the update though.
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-05-2020, 01:00 AM   #24
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

By the way, the finger tips (the fat "O"s) don't show up anymore. I will post a screen shot.



Could it be a copy paste error? That some information got lost here in the forum?

Yes. Its definitionally a copy paste error. In the code show up two weird characters. If I replace them with 0 and O it works like expected.


With O and o it looks fine to me:

__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆

Last edited by Eliseat; 07-05-2020 at 01:21 AM.
Eliseat is offline   Reply With Quote
Old 07-05-2020, 01:27 AM   #25
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Quote:
Originally Posted by WyattRice View Post
Wonderful!
Thanks for sharing this.

Is there a way you could add rotate so that the nut is on the left?
Just curious.
Anyway, Many thanks!

Wyatt
You could add another video processor with the preset opacity, zoom, pan and rotate it -90 degree. But this also rotates the chord phrase which gets hard to read then.
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-05-2020, 03:37 AM   #26
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

I just updated the most recent version. I put an X above unused strings. But if you have a barre that uses that string, it's not really unused. So I made it so you can control whether or not there's an X. If you put a space in the #frets string, that lets you hide the X when you need to. Example:

#frets = "x3x2xx", #barre = "621" (wrong)
#frets = " 3 2 x", #barre = "621" (right)

The finger-spots do show up for me. They are a unicode character, solidSpot in the code. I did fix a bug that might solve the problem, let me know.
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html

Last edited by Kite; 07-05-2020 at 03:58 AM.
Kite is offline   Reply With Quote
Old 07-05-2020, 03:55 AM   #27
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

If you can't get the unicode to work, the solid spot can be "n" in the webdings font. The "x" can be a regular letter, or use "r" in the same font. The hollow spot can be the "m" in the wingdings font.

The problem is, different computers have different fonts installed, so you may have to install something to get webdings or unicode to work...
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-05-2020, 07:16 AM   #28
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Cool. Many thanks, Kite. I will take a look at it and give you feedback. This plugin is such a great idea. And its kind of fun for me, to get a bit into programming again, even if its only simple stuff.
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-05-2020, 08:40 PM   #29
pingosimon
Human being with feelings
 
Join Date: Nov 2018
Posts: 61
Default

Kite, this is awesome!

Eliseat, I love the Chord Root and Chord Type knobs. Super useful. And easy enough, even for me with no coding knowledge, to figure out how to add my own suffixes.
.....but yours doesn't work for me! Nothing shows up on the video screen.

I tried naming the chord by item name, by removing that commented line. It works, but man, that'd take a long time. Is there a way for the processor to grab the name from text inside a blank item? Or does someone know a good workflow for editing Item Properties?
pingosimon is offline   Reply With Quote
Old 07-06-2020, 01:01 AM   #30
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Quote:
Originally Posted by pingosimon View Post
Kite, this is awesome!

Eliseat, I love the Chord Root and Chord Type knobs. Super useful. And easy enough, even for me with no coding knowledge, to figure out how to add my own suffixes.
.....but yours doesn't work for me! Nothing shows up on the video screen.

I tried naming the chord by item name, by removing that commented line. It works, but man, that'd take a long time. Is there a way for the processor to grab the name from text inside a blank item? Or does someone know a good workflow for editing Item Properties?
It doesn't work for you? How could this be? Do you mean my version doesn't work but Kites does? That seems really weird and only could be if the video processor works different on different systems. I posted my version in the JSFX section, and as far es I know Fabian was able to test it like expected.

Here is the latest version with Kites bugfixes and additions. Plus my chord parameter contribution.

Code:
// overlay chord grid
// to omit the chord name, set it to "", to center it, add trailing spaces
// numStrings = length of #frets. 0 = open, x or space = unused (space = no X shown)
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string
root == 0 ? root_str="C";
root == 1 ? root_str="C#";
root == 2 ? root_str="D";
root == 3 ? root_str="D#";
root == 4 ? root_str="E";
root == 5 ? root_str="F";
root == 6 ? root_str="F#";
root == 7 ? root_str="G";
root == 8 ? root_str="G#";
root == 9 ? root_str="A";
root == 10 ? root_str="A#";
root == 11 ? root_str="B";

chtype == 1 ? chtype_str="maj";
chtype == 2 ? chtype_str="min";
chtype == 3 ? chtype_str="7";

#chord = sprintf(#, "%s %s ", root_str, chtype_str);

root == 0 && chtype == 1 ? (#frets = "x32010";#barre = "")  :
root == 1 && chtype == 1 ? (#frets = "x06660"; #barre = "514")  :
root == 2 && chtype == 1 ? (#frets = "xx0232"; #barre = "")  :
root == 3 && chtype == 1 ? (#frets = "x65040"; #barre = "313")  :
root == 4 && chtype == 1 ? (#frets = "022100"; #barre = "")  :
root == 5 && chtype == 1 ? (#frets = "033200"; #barre = "611")  :
root == 6 && chtype == 1 ? (#frets = "044300"; #barre = "612")  :
root == 7 && chtype == 1 ? (#frets = "320003"; #barre = "")  :
root == 8 && chtype == 1 ? (#frets = "066500"; #barre = "614")  :
root == 9 && chtype == 1 ? (#frets = "x02220"; #barre = "")  :
root == 10 && chtype == 1 ? (#frets = "x03330"; #barre = "511")  :
root == 11 && chtype == 1 ? (#frets = "x04440"; #barre = "512")  :

(#frets = "000000"; #barre = "";) ;
//#chord = "Ab7    ";
//#frets = " 3 2  ";              // relative to the 1st fret shown
//#barre = "611";
#barre2 = "";
#barre3 = "";

//@param1:root 'Root' 0 0 11 6 1
//@param2:chtype 'Chord type' 1 1 3 1 1
//@param3:xpos 'x position' 0.5 0 1 0.5 0.01
//@param4:ypos 'y position' 0.5 0 1 0.5 0.01
//@param5:numFrets 'number of frets' 5 4 8 6 1
//@param6:startFret 'starting fret number' 1 1 21 11 1

//@param7:fontSize 'font size' 60 20 120 70 5
//@param8:border 'border' 20 5 45 30 1
//@param9:gap 'gap under name' 25 25 50 25 1
//@param10:colwid 'string spacing' 40 20 60 40 2
//@param11:rowht 'fret spacing' 40 20 60 40 2
//@param12:LT 'line thickness' 5 1 9 5 1
//@param13:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02
//@param15:opacity 'opacity' 1 0 1 0.5 0.01
//@param16:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "O"; hollowSpot = "O"; ex = "✖";  // unicode 2B24, 2B55 and 2716
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, opacity);                        // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    //strcmp (#s, "^") == 0 ? (f = font3);         // (microtonal notation)
    //strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                   //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                         // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize * rowht, font1);              //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48;              // zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
barreH = spotSize * rowht;
loop (3,                                            // kluge
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink
    gfx_fillRect (xpos2, ypos2 - barreH/2, barreLen, barreH);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
  #barre = #barre2; #barre2 = #barre3;    // kluge to avoid learning about functions!
);
Its possible, that there are copy and paste errors relating to the symbols used as O and X. Please check it out. I plan to put more chords in there and also to optimize the coding. But I'm a noob so don't expect to much.
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-06-2020, 01:59 PM   #31
Erdan
Human being with feelings
 
Join Date: Mar 2019
Location: France
Posts: 5
Default Added Minor, 7 and Maj7 Chord

Nice job !

I've added Minor, 7 chords charts and Maj7 Chords and some corrections (from my point of view)

Code:
// overlay chord grid
// to omit the chord name, set it to "", to center it, add trailing spaces
// numStrings = length of #frets. 0 = open, x or space = unused (space = no X shown)
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string
root == 0 ? root_str="C";
root == 1 ? root_str="C#";
root == 2 ? root_str="D";
root == 3 ? root_str="D#";
root == 4 ? root_str="E";
root == 5 ? root_str="F";
root == 6 ? root_str="F#";
root == 7 ? root_str="G";
root == 8 ? root_str="G#";
root == 9 ? root_str="A";
root == 10 ? root_str="A#";
root == 11 ? root_str="B";

chtype == 1 ? chtype_str="maj";
chtype == 2 ? chtype_str="min";
chtype == 3 ? chtype_str="7";
chtype == 4 ? chtype_str="Maj7";

#chord = sprintf(#, "%s %s ", root_str, chtype_str);

// Major
root == 0 && chtype == 1 ? (#frets = "x32010";#barre = "")  :
root == 1 && chtype == 1 ? (#frets = "x 666 "; #barre = "514")  :
root == 2 && chtype == 1 ? (#frets = "xx0232"; #barre = "")  :
root == 3 && chtype == 1 ? (#frets = "x65 4 "; #barre = "313")  :
root == 4 && chtype == 1 ? (#frets = "022100"; #barre = "")  :
root == 5 && chtype == 1 ? (#frets = " 332  "; #barre = "611")  :
root == 6 && chtype == 1 ? (#frets = " 443  "; #barre = "612")  :
root == 7 && chtype == 1 ? (#frets = "320003"; #barre = "")  :
root == 8 && chtype == 1 ? (#frets = " 665  "; #barre = "614")  :
root == 9 && chtype == 1 ? (#frets = "x02220"; #barre = "")  :
root == 10 && chtype == 1 ? (#frets = "x 333 "; #barre = "511")  :
root == 11 && chtype == 1 ? (#frets = "x 444 "; #barre = "512")  :

// Minor
root == 0 && chtype == 2? (#frets = "x3554 ";#barre = "513")  :
root == 1 && chtype == 2 ? (#frets = "x 665 "; #barre = "514")  :
root == 2 && chtype == 2 ? (#frets = "xx0231"; #barre = "")  :
root == 3 && chtype == 2 ? (#frets = "x4665 "; #barre = "514")  :
root == 4 && chtype == 2 ? (#frets = "022000"; #barre = "")  :
root == 5 && chtype == 2 ? (#frets = " 33   "; #barre = "611")  :
root == 6 && chtype == 2 ? (#frets = " 44   "; #barre = "612")  :
root == 7 && chtype == 2 ? (#frets = " 55   "; #barre = "613")  :
root == 8 && chtype == 2 ? (#frets = " 66   "; #barre = "614")  :
root == 9 && chtype == 2 ? (#frets = "x02210"; #barre = "")  :
root == 10 && chtype == 2 ? (#frets = "x 332 "; #barre = "511")  :
root == 11 && chtype == 2? (#frets = "x 443 "; #barre = "512")  :

// Dominant 7
root == 0 && chtype == 3 ? (#frets = "x32310";#barre = "")  :
root == 1 && chtype == 3 ? (#frets = "x 6 6 "; #barre = "514")  :
root == 2 && chtype == 3 ? (#frets = "xx0212"; #barre = "")  :
root == 3 && chtype == 3 ? (#frets = "x 7 7 "; #barre = "5156")  :
root == 4 && chtype == 3 ? (#frets = "020100"; #barre = "")  :
root == 5 && chtype == 3 ? (#frets = " 3 2  "; #barre = "611")  :
root == 6 && chtype == 3 ? (#frets = " 4 3  "; #barre = "612")  :
root == 7 && chtype == 3 ? (#frets = "320001"; #barre = "")  :
root == 8 && chtype == 3 ? (#frets = " 6 5  "; #barre = "614")  :
root == 9 && chtype == 3 ? (#frets = "x02020"; #barre = "")  :
root == 10 && chtype == 3 ? (#frets = "x 3 3 "; #barre = "511")  :
root == 11 && chtype == 3 ? (#frets = "x 4 4 "; #barre = "512")  :

// Maj7
root == 0 && chtype == 4 ? (#frets = "x32000";#barre = "")  :
root == 1 && chtype == 4 ? (#frets = "x 656 "; #barre = "514")  :
root == 2 && chtype == 4 ? (#frets = "xx0222"; #barre = "")  :
root == 3 && chtype == 4 ? (#frets = "x 767 "; #barre = "5156")  :
root == 4 && chtype == 4 ? (#frets = "021100"; #barre = "")  :
root == 5 && chtype == 4 ? (#frets = "1x2210"; #barre = "")  :
root == 6 && chtype == 4 ? (#frets = "2x332x"; #barre = "")  :
root == 7 && chtype == 4 ? (#frets = "320000"; #barre = "")  :
root == 8 && chtype == 4 ? (#frets = "4x554x"; #barre = "")  :
root == 9 && chtype == 4 ? (#frets = "x02120"; #barre = "")  :
root == 10 && chtype == 4 ? (#frets = "x 323 "; #barre = "511")  :
root == 11 && chtype == 4 ? (#frets = "x 434 "; #barre = "512")  :

(#frets = "000000"; #barre = "";) ;
//#chord = "Ab7    ";
//#frets = " 3 2  ";              // relative to the 1st fret shown
//#barre = "611";
#barre2 = "";
#barre3 = "";

//@param1:root 'Root' 0 0 11 6 1
//@param2:chtype 'Chord type' 1 1 4 1 1
//@param3:xpos 'x position' 0.5 0 1 0.5 0.01
//@param4:ypos 'y position' 0.5 0 1 0.5 0.01
//@param5:numFrets 'number of frets' 5 4 8 6 1
//@param6:startFret 'starting fret number' 1 1 21 11 1

//@param7:fontSize 'font size' 60 20 120 70 5
//@param8:border 'border' 20 5 45 30 1
//@param9:gap 'gap under name' 25 25 50 25 1
//@param10:colwid 'string spacing' 40 20 60 40 2
//@param11:rowht 'fret spacing' 40 20 60 40 2
//@param12:LT 'line thickness' 5 1 9 5 1
//@param13:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02
//@param15:opacity 'opacity' 1 0 1 0.5 0.01
//@param16:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "O"; hollowSpot = "O"; ex = "✖";  // unicode 2B24, 2B55 and 2716
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, opacity);                        // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    //strcmp (#s, "^") == 0 ? (f = font3);         // (microtonal notation)
    //strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                   //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                         // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize * rowht, font1);              //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48;              // zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
barreH = spotSize * rowht;
loop (3,                                            // kluge
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink
    gfx_fillRect (xpos2, ypos2 - barreH/2, barreLen, barreH);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
  #barre = #barre2; #barre2 = #barre3;    // kluge to avoid learning about functions!
);

Last edited by Erdan; 07-06-2020 at 02:04 PM.
Erdan is offline   Reply With Quote
Old 07-06-2020, 02:56 PM   #32
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Great. That's how a nice idea gets high like a rocket!
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆
Eliseat is offline   Reply With Quote
Old 07-07-2020, 12:53 AM   #33
Eliseat
Human being with feelings
 
Eliseat's Avatar
 
Join Date: Mar 2018
Location: Cologne
Posts: 1,318
Default

Here the last version with Erdans filled chords but with a more efficient code thru arrays. (Thanks to Fabian.) This script works really fluidly. You can automate the parameters to follow a whole song with ease. Just amazing! I hope, Justin realizes how much potential the video section has, if he sees such great contributions. Lots of possibilities. But still some annoying hurdles.

Code:
// Guita chord overlay
// to omit the chord name, set it to "", to center it, add trailing spaces
// numStrings = length of #frets. 0 = open, x or space = unused (space = no X shown)
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string

root_array = 10000; // This sets the memory address for start
mem_set_values(root_array, "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B");

chtype_array = 10016;
mem_set_values(chtype_array, "unused", "maj", "min", "7", "Maj7" );

root_str = root_array[root];

chtype_str = chtype_array[chtype];

#chord = sprintf(#, "%s %s ", root_str, chtype_str);

// Major
root == 0 && chtype == 1 ? (#frets = "x32010";#barre = "")  :
root == 1 && chtype == 1 ? (#frets = "x 666 "; #barre = "514")  :
root == 2 && chtype == 1 ? (#frets = "xx0232"; #barre = "")  :
root == 3 && chtype == 1 ? (#frets = "x65 4 "; #barre = "313")  :
root == 4 && chtype == 1 ? (#frets = "022100"; #barre = "")  :
root == 5 && chtype == 1 ? (#frets = " 332  "; #barre = "611")  :
root == 6 && chtype == 1 ? (#frets = " 443  "; #barre = "612")  :
root == 7 && chtype == 1 ? (#frets = "320003"; #barre = "")  :
root == 8 && chtype == 1 ? (#frets = " 665  "; #barre = "614")  :
root == 9 && chtype == 1 ? (#frets = "x02220"; #barre = "")  :
root == 10 && chtype == 1 ? (#frets = "x 333 "; #barre = "511")  :
root == 11 && chtype == 1 ? (#frets = "x 444 "; #barre = "512")  :

// Minor
root == 0 && chtype == 2? (#frets = "x3554 ";#barre = "513")  :
root == 1 && chtype == 2 ? (#frets = "x 665 "; #barre = "514")  :
root == 2 && chtype == 2 ? (#frets = "xx0231"; #barre = "")  :
root == 3 && chtype == 2 ? (#frets = "x4665 "; #barre = "514")  :
root == 4 && chtype == 2 ? (#frets = "022000"; #barre = "")  :
root == 5 && chtype == 2 ? (#frets = " 33   "; #barre = "611")  :
root == 6 && chtype == 2 ? (#frets = " 44   "; #barre = "612")  :
root == 7 && chtype == 2 ? (#frets = " 55   "; #barre = "613")  :
root == 8 && chtype == 2 ? (#frets = " 66   "; #barre = "614")  :
root == 9 && chtype == 2 ? (#frets = "x02210"; #barre = "")  :
root == 10 && chtype == 2 ? (#frets = "x 332 "; #barre = "511")  :
root == 11 && chtype == 2? (#frets = "x 443 "; #barre = "512")  :

// Dominant 7
root == 0 && chtype == 3 ? (#frets = "x32310";#barre = "")  :
root == 1 && chtype == 3 ? (#frets = "x 6 6 "; #barre = "514")  :
root == 2 && chtype == 3 ? (#frets = "xx0212"; #barre = "")  :
root == 3 && chtype == 3 ? (#frets = "x 7 7 "; #barre = "5156")  :
root == 4 && chtype == 3 ? (#frets = "020100"; #barre = "")  :
root == 5 && chtype == 3 ? (#frets = " 3 2  "; #barre = "611")  :
root == 6 && chtype == 3 ? (#frets = " 4 3  "; #barre = "612")  :
root == 7 && chtype == 3 ? (#frets = "320001"; #barre = "")  :
root == 8 && chtype == 3 ? (#frets = " 6 5  "; #barre = "614")  :
root == 9 && chtype == 3 ? (#frets = "x02020"; #barre = "")  :
root == 10 && chtype == 3 ? (#frets = "x 3 3 "; #barre = "511")  :
root == 11 && chtype == 3 ? (#frets = "x 4 4 "; #barre = "512")  :

// Maj7
root == 0 && chtype == 4 ? (#frets = "x32000";#barre = "")  :
root == 1 && chtype == 4 ? (#frets = "x 656 "; #barre = "514")  :
root == 2 && chtype == 4 ? (#frets = "xx0222"; #barre = "")  :
root == 3 && chtype == 4 ? (#frets = "x 767 "; #barre = "5156")  :
root == 4 && chtype == 4 ? (#frets = "021100"; #barre = "")  :
root == 5 && chtype == 4 ? (#frets = "1x2210"; #barre = "")  :
root == 6 && chtype == 4 ? (#frets = "2x332x"; #barre = "")  :
root == 7 && chtype == 4 ? (#frets = "320000"; #barre = "")  :
root == 8 && chtype == 4 ? (#frets = "4x554x"; #barre = "")  :
root == 9 && chtype == 4 ? (#frets = "x02120"; #barre = "")  :
root == 10 && chtype == 4 ? (#frets = "x 323 "; #barre = "511")  :
root == 11 && chtype == 4 ? (#frets = "x 434 "; #barre = "512")  :

(#frets = "000000"; #barre = "";) ;
//#chord = "Ab7    ";
//#frets = " 3 2  ";              // relative to the 1st fret shown
//#barre = "611";
#barre2 = "";
#barre3 = "";

//@param1:root 'Root' 0 0 11 6 1
//@param2:chtype 'Chord type' 1 1 4 1 1
//@param4:xpos 'x position' 0.5 0 1 0.5 0.01
//@param5:ypos 'y position' 0.5 0 1 0.5 0.01
//@param6:numFrets 'number of frets' 5 4 8 6 1
//@param7:startFret 'starting fret number' 1 1 21 11 1

//@param9:fontSize 'font size' 60 20 120 70 5
//@param10:border 'border' 20 5 45 30 1
//@param11:gap 'gap under name' 25 25 50 25 1
//@param12:colwid 'string spacing' 40 20 60 40 2
//@param13:rowht 'fret spacing' 40 20 60 40 2
//@param14:LT 'line thickness' 5 1 9 5 1
//@param15:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02
//@param17:opacity 'opacity' 1 0 1 0.5 0.01
//@param18:ignoreinput 'ignore input' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "O"; hollowSpot = "O"; ex = "✖";  // unicode 2B24, 2B55 and 2716
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, opacity);                        // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    //strcmp (#s, "^") == 0 ? (f = font3);         // (microtonal notation)
    //strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                   //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                         // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize * rowht, font1);              //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48;              // zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
barreH = spotSize * rowht;
loop (3,                                            // kluge
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink
    gfx_fillRect (xpos2, ypos2 - barreH/2, barreLen, barreH);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
  #barre = #barre2; #barre2 = #barre3;    // kluge to avoid learning about functions!
);



Automation:





Greetings
Eli
__________________
☆.。.:*・°☆.。.:*・°☆.。.:*・°☆REAPER//✿◔‿◔)°☆.。.:*・°☆.。.:*・°☆

Last edited by Eliseat; 07-07-2020 at 12:58 AM.
Eliseat is offline   Reply With Quote
Old 07-07-2020, 03:11 AM   #34
dahya
Human being with feelings
 
Join Date: Oct 2019
Posts: 82
Default

Woah this looks so good !!! I'm not a guitar player, but this looks so useful, for example if I have a guitarist come in to play some guitar chords, this is just what they'd need if they don't know the song !! Thanks for contributing !
dahya is offline   Reply With Quote
Old 07-08-2020, 09:53 AM   #35
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 5,867
Default

Here is a version that should be slightly more efficient and so perhaps run smoother. I also added a switch to invert the drawing, black background and white foreground.

Code:
// Guita chord overlay - with arrays and invert switch
// to omit the chord name, set it to "", to center it, add trailing spaces
// numStrings = length of #frets. 0 = open, x or space = unused (space = no X shown)
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string

init < 1 ? // should we initialize the arrays?
(
  root_array = 10000; // Array for the rrot notes
  mem_set_values(root_array, " C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B");

  chtype_array = 10016; // Array for the chord types (0th element is not used)
  mem_set_values(chtype_array, "unused", "maj", "min", "7", "Maj7" );

  frets_array1 = 10032; // Major
  mem_set_values(frets_array1, "x32010", "x 666 ", "xx0232", "x65 4 ", "022100", " 332  ", " 443  ", "320003", " 665  ", "x02220", "x 333 ", "x 444 ");
  barre_array1 = 10050; 
  mem_set_values(barre_array1, "", "514", "", "313", "", "611", "612", "", "614", "", "511", "512");

  frets_array2 = 10064; // Minor
  mem_set_values(frets_array2, "x3554 ", "x 665 ", "xx0231", "x4665 ", "022000", " 33   ", " 44   ", " 55   ", " 66   ", "x02210", "x 332 ", "x 443 ");
  barre_array2 = 10080;
  mem_set_values(barre_array2, "513", "514", "", "514", "", "611", "612", "613", "614", "", "511", "512");

  frets_array3 = 10092; // Dominant 7
  mem_set_values(frets_array3, "x32310", "x 6 6 ", "xx0212", "x 7 7 ", "020100", " 3 2  ", " 4 3  ", "320001", " 6 5  ", "x02020", "x 3 3 ", "x 4 4 ");
  barre_array3 = 10108;
  mem_set_values(barre_array3, "", "514", "", "5156", "", "611", "612", "", "614", "", "511", "512");

  frets_array4 = 10120; // Maj7
  mem_set_values(frets_array4, "x32000", "x 656 ", "xx0222", "x 767 ", "021100", "1x2210", "2x332x", "320000", "4x554x", "x02120", "x 323 ", "x 434 ");
  barre_array4 = 10132;
  mem_set_values(barre_array4, "", "514", "", "5156", "", "", "", "", "", "", "511", "512");

  arr_of_frets = 12000; // Array of frets_arrays, is it possible?
  mem_set_values(arr_of_frets, frets_array1, frets_array2, frets_array3, frets_array4);
  arr_of_barres = 12500; 
  mem_set_values(arr_of_barres, barre_array1, barre_array2, barre_array3, barre_array4);
  
  init = 42; // Do not initialize again
);

root_str = root_array[root];
chtype_str = chtype_array[chtype];

#chord = sprintf(#, "%s %s ", root_str, chtype_str);
// #frets = "000000"; #barre = "";
#frets = arr_of_frets[chtype-1][root]; 
#barre = arr_of_barres[chtype-1][root];
//#chord = "Ab7    ";
//#frets = " 3 2  ";              // relative to the 1st fret shown
//#barre = "611";
#barre2 = "";
#barre3 = "";

//@param1:root 'Root' 0 0 11 6 1
//@param2:chtype 'Chord type' 1 1 4 1 1

//@param4:xpos 'x position' 0.5 0 1 0.5 0.01
//@param5:ypos 'y position' 0.5 0 1 0.5 0.01
//@param6:numFrets 'number of frets' 5 4 8 6 1
//@param7:startFret 'starting fret number' 1 1 21 11 1

//@param9:fontSize 'font size' 60 20 120 70 5
//@param10:border 'border' 20 5 45 30 1
//@param11:gap 'gap under name' 25 25 50 25 1
//@param12:colwid 'string spacing' 40 20 60 40 2
//@param13:rowht 'fret spacing' 40 20 60 40 2
//@param14:LT 'line thickness' 5 1 9 5 1
//@param15:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02

//@param17:opacity 'opacity' 1 0 1 0.5 0.01
//@param18:ignoreinput 'ignore input' 0 0 1 0.5 1

//@param20:invert 'invert' 0 0 1 0.5 1

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "O"; hollowSpot = "O"; ex = "✖";  // unicode 2B24, 2B55 and 2716
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
invert == 0 ? // invert means black bg and white fg, so just skip this
(
  gfx_fillrect (xpos, ypos, width, height);
  gfx_set (0, 0, 0, opacity);                        // black grid
);

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    //strcmp (#s, "^") == 0 ? (f = font3);         // (microtonal notation)
    //strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                   //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                         // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize * rowht, font1);              //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48;              // zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
barreH = spotSize * rowht;
loop (3,                                            // kluge
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink
    gfx_fillRect (xpos2, ypos2 - barreH/2, barreLen, barreH);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
  #barre = #barre2; #barre2 = #barre3;    // kluge to avoid learning about functions!
);
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 07-08-2020, 03:43 PM   #36
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

I finally took the time to look at the version with root/type pasrameter. Some thoughts:

1) Someone pointed out in another thread that it's a good idea to put the date and author in the code, to keep track of versions if nothing else.

2) It looks WAY better with the unicode characters for the finger-spots. Apparently Eliseat had problems copying and pasting the unicode. So the effect didn't work for her, and the spots didn't show up. If this happens, you can fix it by entering the unicode characters directly into the editor yourself. See https://en.wikipedia.org/wiki/Unicode_input, or just google "enter unicode character windows", "enter unicode character OSX", or whatever. You may need to install a font. See also the webdings workaround upthread. But if you're serious about making instructional videos, you need to get unicode characters working on your computer. It shouldn't be that hard. Here's what you want to end up with:
Code:
solidSpot = "⬤"; hollowSpot = "⭕"; ex = "✖"; // unicode 2B24, 2B55 and 2716
3) Look, everyone, if you play I - IV - V in F, you want to call the IV chord a Bb chord. Calling it an A# chord is really confusing, and just plain wrong. You might say, what's the difference, A# major and Bb major sound the same. Well, it's like writing "C mayjurr". Sure, mayjurr and major sound the same, but mayjurr is weird and jarring, and just plain wrong. And even if you don't mind A#, not everyone will agree with you. It's much better to give the user the choice of A# vs. Bb.

4) Currently, when a chord goes up above the 5th fret, it gets chopped off. For those chords, the fret numbers need to be decreased and the "starting fret" parameter needs to be set appropriately. This puts everything in a 4-fret range, so the default # of frets can be lowered from 5 to 4.

5) The chord frettings are somewhat arbitrary. Sometimes you want to play A7 as 002020 and sometimes as 002223.

I reached the character limit for posts in this forum, so the actual code will be in the next post. I fixed everything except for #5.

Changes:
Added the date & the authors to the 2nd line
Moved the param stuff to the top of the code, easier to find
Added the unicode characters back in
Got rid of the loop at the end for the 2 unused barres, more efficient
Fixed the root naming problem
Fixed the starting fret problem
Removed the knobs for numFrets and startFret, since they are no longer needed
Set the # of frets down to 4, more compact
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html
Kite is offline   Reply With Quote
Old 07-08-2020, 03:44 PM   #37
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 189
Default

OK, so here's the latest version:

Code:
// overlay chord grid parametric root & type
// July 8, 2020 Kite / Eliseat / Erdan / Fabian
// numStrings = length of #frets. 0 = open, x or space = unused (space = no X shown)
// barre strings have 3 numbers: start string, end string and fret
// if no 3rd number, then fret = 1. if no 2nd number, then end string = start string

//@param1:root 'Root' 0 0 11 5.5 1
//@param2:chtype 'Chord type' 1 1 4 2 1
//@param3:useFlats 'Use flats?' 1 0 1 0.5 1
//@param4:xpos 'x position' 0.5 0 1 0.5 0.01
//@param5:ypos 'y position' 0.5 0 1 0.5 0.01
//@param6:fontSize 'font size' 60 20 120 70 5
//@param7:border 'border' 20 5 45 30 1
//@param8:gap 'gap under name' 25 25 50 25 1

//@param10:colwid 'string spacing' 40 20 60 40 2
//@param11:rowht 'fret spacing' 40 20 60 40 2
//@param12:LT 'line thickness' 5 1 9 5 1
//@param13:spotSize 'finger-spot size' 0.7 0.5 1 0.75 0.02

//@param15:opacity 'opacity' 1 0 1 0.5 0.01
//@param16:ignoreinput 'ignore input' 0 0 1 0.5 1

root == 0 ? root_str="C";
root == 1 ? root_str="C#";
root == 2 ? root_str="D";
root == 3 ? root_str="D#";
root == 4 ? root_str="E";
root == 5 ? root_str="F";
root == 6 ? root_str="F#";
root == 7 ? root_str="G";
root == 8 ? root_str="G#";
root == 9 ? root_str="A";
root == 10 ? root_str="A#";
root == 11 ? root_str="B";

useFlats ? (
root == 1 ? root_str="Db";
root == 3 ? root_str="Eb";
root == 6 ? root_str="Gb";
root == 8 ? root_str="Ab";
root == 10 ? root_str="Bb";
);

chtype == 1 ? chtype_str="maj";
chtype == 2 ? chtype_str="min";
chtype == 3 ? chtype_str="7";
chtype == 4 ? chtype_str="Maj7";

#chord = sprintf(#, "%s %s ", root_str, chtype_str);
numFrets = 4; startFret = 1;

// Major
root ==  0 && chtype == 1 ? (#frets = "x32010"; #barre = "")  :
root ==  1 && chtype == 1 ? (#frets = "x 333 "; #barre = "511"; startFret = 4)  :
root ==  2 && chtype == 1 ? (#frets = "xx0232"; #barre = "")  :
root ==  3 && chtype == 1 ? (#frets = "x43 2 "; #barre = "311"; startFret = 3)  :
root ==  4 && chtype == 1 ? (#frets = "022100"; #barre = "")  :
root ==  5 && chtype == 1 ? (#frets = " 332  "; #barre = "611")  :
root ==  6 && chtype == 1 ? (#frets = " 443  "; #barre = "612")  :
root ==  7 && chtype == 1 ? (#frets = "320003"; #barre = "")  :
root ==  8 && chtype == 1 ? (#frets = " 332  "; #barre = "611"; startFret = 4)  :
root ==  9 && chtype == 1 ? (#frets = "x02220"; #barre = "")  :
root == 10 && chtype == 1 ? (#frets = "x 333 "; #barre = "511")  :
root == 11 && chtype == 1 ? (#frets = "x 444 "; #barre = "512")  :

// Minor
root ==  0 && chtype == 2 ? (#frets = "x 332 "; #barre = "511"; startFret = 3)  :
root ==  1 && chtype == 2 ? (#frets = "x 332 "; #barre = "511"; startFret = 4)  :
root ==  2 && chtype == 2 ? (#frets = "xx0231"; #barre = "")  :
root ==  3 && chtype == 2 ? (#frets = "x 332 "; #barre = "511"; startFret = 4)  :
root ==  4 && chtype == 2 ? (#frets = "022000"; #barre = "")  :
root ==  5 && chtype == 2 ? (#frets = " 33   "; #barre = "611")  :
root ==  6 && chtype == 2 ? (#frets = " 44   "; #barre = "612")  :
root ==  7 && chtype == 2 ? (#frets = " 33   "; #barre = "611"; startFret = 3)  :
root ==  8 && chtype == 2 ? (#frets = " 33   "; #barre = "611"; startFret = 4)  :
root ==  9 && chtype == 2 ? (#frets = "x02210"; #barre = "")  :
root == 10 && chtype == 2 ? (#frets = "x 332 "; #barre = "511")  :
root == 11 && chtype == 2 ? (#frets = "x 443 "; #barre = "512")  :

// Dominant 7
root ==  0 && chtype == 3 ? (#frets = "x32310"; #barre = "")  :
root ==  1 && chtype == 3 ? (#frets = "x 3 3 "; #barre = "511"; startFret = 4)  :
root ==  2 && chtype == 3 ? (#frets = "xx0212"; #barre = "")  :
root ==  3 && chtype == 3 ? (#frets = "x 3 3 "; #barre = "511"; startFret = 5)  :
root ==  4 && chtype == 3 ? (#frets = "020100"; #barre = "")  :
root ==  5 && chtype == 3 ? (#frets = " 3 2  "; #barre = "611")  :
root ==  6 && chtype == 3 ? (#frets = " 4 3  "; #barre = "612")  :
root ==  7 && chtype == 3 ? (#frets = "320001"; #barre = "")  :
root ==  8 && chtype == 3 ? (#frets = " 3 2  "; #barre = "611"; startFret = 4)  :
root ==  9 && chtype == 3 ? (#frets = "x02020"; #barre = "")  :
root == 10 && chtype == 3 ? (#frets = "x 3 3 "; #barre = "511")  :
root == 11 && chtype == 3 ? (#frets = "x 4 4 "; #barre = "512")  :

// Maj7
root ==  0 && chtype == 4 ? (#frets = "x32000"; #barre = "")  :
root ==  1 && chtype == 4 ? (#frets = "x 323 "; #barre = "511"; startFret = 4)  :
root ==  2 && chtype == 4 ? (#frets = "xx0222"; #barre = "")  :
root ==  3 && chtype == 4 ? (#frets = "x 323 "; #barre = "511"; startFret = 5)  :
root ==  4 && chtype == 4 ? (#frets = "021100"; #barre = "")  :
root ==  5 && chtype == 4 ? (#frets = "1x2210"; #barre = "")  :
root ==  6 && chtype == 4 ? (#frets = "2x332x"; #barre = "")  :
root ==  7 && chtype == 4 ? (#frets = "320000"; #barre = "")  :
root ==  8 && chtype == 4 ? (#frets = "1x221x"; #barre = ""; startFret = 4)  :
root ==  9 && chtype == 4 ? (#frets = "x02120"; #barre = "")  :
root == 10 && chtype == 4 ? (#frets = "x 323 "; #barre = "511")  :
root == 11 && chtype == 4 ? (#frets = "x 434 "; #barre = "512")  :
(#frets = "000000"; #barre = "";) ;

//#chord = "Ab7    ";
//#frets = " 3 2  ";              // relative to the 1st fret shown
//#barre = "611";
//#barre2 = "";
//#barre3 = "";

fontRatio = 0.75;                        // side number is 75% size of top name
font1 = "Times New Roman";               // default font
font2 = "MS Reference Sans Serif";       // for sharps and flats
font3 = "Arial Narrow";                  // for ups and downs (microtonal)
sharp = "♯"; flat  = "♭";                // unicode 266F and 266D
solidSpot = "⬤"; hollowSpot = "⭕"; ex = "✖";  // unicode 2B24, 2B55 and 2716
input = ignoreinput ? -2:0;
project_wh_valid === 0 ? input_info (input, project_w, project_h);
gfx_a2 = 0;
gfx_blit (input, 1);
//strlen (#chord) == 0 ? input_get_name (-1, #chord);
gfx_setfont (fontSize, font1);            // use default font for now
gfx_str_measure (#chord, defW, defH);     // width & height in default font
#sideNum = " ";
str_setchar (#sideNum, 0, (startFret % 10) + 48);
startFret >= 10 ? (
  strcat (#sideNum, #sideNum);
  str_setchar (#sideNum, 0, (startFret / 10) + 48);
);
gfx_setfont (fontRatio * fontSize);
gfx_str_measure (#sideNum, sideW, sideH);
numStrings = strlen (#frets);
width = (numStrings - 1) * colwid + 2.5 * border;  // a little extra border
startFret > 1 ? width += sideW + border;
height = (numFrets + 0.7) * rowht + 2 * border;
strlen (#chord) > 0 ? height += defH + gap;
xpos *= (project_w - width);                       // convert from percent to pixels
ypos *= (project_h - height); 
gfx_set (1, 1, 1, opacity);                        // white background
gfx_fillrect (xpos, ypos, width, height);
gfx_set (0, 0, 0, opacity);                        // black grid

strlen (#chord) > 0 ? (                            //====== CHORD NAME ========
  xpos2 = xpos + width - border - defW;
  ypos2 = ypos + border;
  i = 0;
  loop (strlen(#chord),
    strcpy_substr (#s, #chord, i, 1);              // #s is Ith character
    f = font1; s = 1; h = 0;                       // s = scale, h = height
    strcmp (#s, "#") == 0 ? (f = font2; #s = sharp; h = 0.2);
    strcmp (#s, "b") == 0 ? (f = font2; #s = flat;  h = 0.2);
    //strcmp (#s, "^") == 0 ? (f = font3);         // (microtonal notation)
    //strcmp (#s, "v") == 0 ? (f = font3; s = 0.9; h = -0.05);
    strcmp (#s, "(") == 0 || strcmp (#s, ")") == 0 ? (s = 0.9; h = 0.05);
    gfx_setfont (s * fontSize, f);
    gfx_str_measure (#s, txtw, txth);
    gfx_str_draw (#s, xpos2, ypos2 - txth * h);
    xpos2 += txtw;
    i += 1;
  );
);

startFret > 1 ? (                                   //======= SIDE LABEL ========
  xpos2 = xpos + border;
  ypos2 = ypos + border + defH + gap + 0.5 * rowht - sideH/2;
  gfx_setfont (fontRatio * fontSize, font1);
  gfx_str_draw (#sideNum, xpos2, ypos2);
);

xpos += border; startFret > 1 ? xpos += sideW + border;  //======== GRID =========
ypos += border; strcmp (#chord,"") ? ypos += defH + gap;
startFret == 1 ?                                         // draw the nut
  gfx_fillRect (xpos - LT/2, ypos - 2*LT, (numStrings - 1) * colwid + LT, 2*LT);
i = 0;
loop (numFrets + 1,                                 //========== FRETS =========
  gfx_fillRect (xpos - LT/2, ypos + i - LT/2, (numStrings - 1) * colwid + LT, LT);
  i += rowht;
);
gfx_setfont (spotSize * rowht, font1);              //========== STRINGS =======
i = 0; xpos2 = xpos;
loop (numStrings,
  gfx_fillRect (xpos2 - LT/2, ypos, LT, (numFrets + 0.6) * rowht);
  fret = str_getchar (#frets, i) - 48;              // zero is the 48th ASCII char
  fret == 0 ? #s = hollowSpot                       // open string gets hollow
  : fret >= 1 && fret <= 9 ? #s = solidSpot         // used string gets solid
  : fret == -16 ? #s = ""                           // space char gets no X
  : (#s = ex; fret = 0);                            // unused string gets an X
  gfx_str_measure (#s, spotW, spotH);
  gfx_str_draw (#s, xpos2 - spotW/2, ypos + rowht * (fret - 0.5) - spotH/1.9);
  xpos2 += colwid;
  i += 1;
);

gfx_str_measure (solidSpot, spotW, spotH);          //======== BARRES =========
barreH = spotSize * rowht;
  strlen (#barre) > 0 ? (
    string1 = str_getchar (#barre, 0) - 48;
    strlen (#barre) < 2 ? string2 = string1
    : string2 = str_getchar (#barre, 1) - 48;
    string1 < string2 ? (
      i = string1; string1 = string2; string2 = i);
    strlen (#barre) < 3 ? fret = 1
    : fret = str_getchar (#barre, 2) - 48;
    xpos2 = xpos + (numStrings - string1) * colwid;
    ypos2 = ypos + rowht * (fret - 0.5);
    barreLen = colwid * (string1 - string2);
    gfx_str_draw (solidSpot, xpos2 - spotW/2, ypos2 - spotH/1.9);
    gfx_str_draw (solidSpot, xpos2 - spotW/2 + barreLen, ypos2 - spotH/1.9);
    // gfx_set (1, 0, 0, 0.5);                      // for debugging, pale pink
    gfx_fillRect (xpos2, ypos2 - barreH/2, barreLen, barreH);
    // gfx_set (0, 0, 0, opacity);                  // for debugging, back to black
  );
__________________
alt-tuner: a microtonal midi plug-in
www.TallKite.com/alt-tuner.html

Last edited by Kite; 07-08-2020 at 04:26 PM.
Kite is offline   Reply With Quote
Old 07-09-2020, 04:32 AM   #38
bobobo
Human being with feelings
 
bobobo's Avatar
 
Join Date: Oct 2014
Posts: 734
Default

wow, very nice.

but maybe an option to lay it down (Zero at the left side, or right for lefthanders) would comfort the experience.

Never looked on a fretboard like this when playing. I guess my neck is way too short.
__________________
Quote:
CLA (about volumelevel) : who gives a shit about that, use your damn ears.
tedious reaper stuff | don't take a look at the tuned_6.0 trial | my Chordgun Variation
Don't forget the __startup.lua
bobobo is offline   Reply With Quote
Old 07-09-2020, 08:59 AM   #39
WyattRice
Human being with feelings
 
WyattRice's Avatar
 
Join Date: Sep 2009
Location: Virginia
Posts: 1,988
Default

Quote:
Originally Posted by Eliseat View Post
You could add another video processor with the preset opacity, zoom, pan and rotate it -90 degree. But this also rotates the chord phrase which gets hard to read then.
Is there a way the chord names could be rotated too?
WyattRice is offline   Reply With Quote
Old 07-09-2020, 10:50 AM   #40
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 271
Default My contrib

My contrib to this wonderfull script :
1- add minor7 and minor7b5 shapes
2- reorder Maj7 - 7 - min7 - min7b5 as you can more visualy see only one finger is moving beetween those types.

I post as an attachement because the forum rules limit post to 10500 and I get 12249.
Attached Files
File Type: txt video-guitar-chords-grid.txt (11.8 KB, 12 views)
daeavelwyn is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 06:12 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.