Plugin Directory

Changeset 3067783


Ignore:
Timestamp:
04/09/2024 03:49:11 PM (2 years ago)
Author:
glewe
Message:

Tagging version 3.6.1

Location:
chordpress
Files:
8 edited
11 copied

Legend:

Unmodified
Added
Removed
  • chordpress/tags/3.6.1/admin/partials/chordpress-admin-options.php

    r2996248 r3067783  
    980980                            <td>
    981981                                <ul class="description" style="list-style: square; margin-left:12px;">
    982                                     <li>The <a href="https://www.chordpro.org" title="ChordPro" rel="nofollow ugc">ChordPro</a> team</li>
    983                                     <li><a href="https://profiles.wordpress.org/rlisle/" title="@rlisle" rel="nofollow ugc">@rlisle</a> for his work on the ChordsAndLyrics plugin that he created in 2009</li>
    984                                     <li>Ahkâm for the beautiful <a href="https://www.freeiconspng.com/img/17579" title="ChordPress Plugin Icon" rel="nofollow ugc">ChordPress Plugin Icon</a></li>
    985                                     <li>The fine people maintaining the <a href="https://github.com/omnibrain/svguitar" title="SVGuitar" rel="nofollow ugc">SVGuitar</a> module</li>
     982                                    <li>The <a href="https://www.chordpro.org" title="ChordPro" rel="nofollow ugc" target="_blank">ChordPro</a> team</li>
     983                                    <li><a href="https://profiles.wordpress.org/rlisle/" title="@rlisle" rel="nofollow ugc" target="_blank">@rlisle</a> for his work on the ChordsAndLyrics plugin that he created in 2009</li>
     984                                    <li>Ahkâm for the beautiful <a href="https://www.freeiconspng.com/img/17579" title="ChordPress Plugin Icon" rel="nofollow ugc" target="_blank">ChordPress Plugin Icon</a></li>
     985                                    <li>The fine people maintaining the <a href="https://github.com/omnibrain/svguitar" title="SVGuitar" rel="nofollow ugc" target="_blank">SVGuitar</a> module</li>
    986986                                </ul>
    987987                            </td>
  • chordpress/tags/3.6.1/chordpress.php

    r2996248 r3067783  
    1717 * Plugin URI:        https://lewe.gitbook.io/lewe-chordpress/
    1818 * Description:       This plugin renders ChordPro formatted text and chord diagrams in WordPress sites.
    19  * Version:           3.6.0
     19 * Version:           3.6.1
    2020 * Author:            George Lewe
    2121 * Author URI:        https://www.lewe.com
     
    3636 */
    3737define('CHORDPRESS_NAME', 'ChordPress');
    38 define('CHORDPRESS_VERSION', '3.6.0');
     38define('CHORDPRESS_VERSION', '3.6.1');
    3939define('CHORDPRESS_AUTHOR', 'George Lewe');
    4040define('CHORDPRESS_AUTHOR_URI', 'https://www.lewe.com');
     
    5252 * This action is documented in includes/class-chordpress-activator.php
    5353 */
    54 function activate_chordpress()
    55 {
    56     require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-activator.php';
    57     ChordPress_Activator::activate();
     54function activate_chordpress() {
     55  require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-activator.php';
     56  ChordPress_Activator::activate();
    5857}
     58
    5959register_activation_hook(__FILE__, 'activate_chordpress');
    6060
     
    6363 * This action is documented in includes/class-chordpress-deactivator.php
    6464 */
    65 function deactivate_chordpress()
    66 {
    67     require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-deactivator.php';
    68     ChordPress_Deactivator::deactivate();
     65function deactivate_chordpress() {
     66  require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-deactivator.php';
     67  ChordPress_Deactivator::deactivate();
    6968}
     69
    7070register_deactivation_hook(__FILE__, 'deactivate_chordpress');
    7171
     
    100100 * @since    1.0.0
    101101 */
    102 function run_chordpress()
    103 {
    104     $plugin = new ChordPress_Plugin();
    105     $plugin->run();
     102function run_chordpress() {
     103  $plugin = new ChordPress_Plugin();
     104  $plugin->run();
    106105}
     106
    107107run_chordpress();
  • chordpress/tags/3.6.1/includes/class-chordpress-renderer.php

    r2996248 r3067783  
    2020 * @author     George Lewe <george@lewe.com>
    2121 */
    22 class ChordPress_Renderer
    23 {
    24     /**
    25      * Guitar chord instance.
    26      *
    27      * @since    2.1.0
    28      * @access   private
    29      * @var      ChordPress_Chord $C Guitar chord instance.
    30      */
    31     private $C;
    32 
    33     /**
    34      * Display H/B notation flag.
    35      *
    36      * @since    1.0.0
    37      * @access   private
    38      * @var      boolean $displayHBNotation Display H/B notation flag.
    39      */
    40     private $displayHBNotation;
    41 
    42     /**
    43      * Hide album flag.
    44      *
    45      * @since    1.0.0
    46      * @access   private
    47      * @var      boolean $hideAlbum Hide album flag.
    48      */
    49     private $hideAlbum;
    50 
    51     /**
    52      * Hide artist flag.
    53      *
    54      * @since    1.0.0
    55      * @access   private
    56      * @var      boolean $hideArtist Hide artist flag.
    57      */
    58     private $hideArtist;
    59 
    60     /**
    61      * Hide chords flag.
    62      *
    63      * @since    1.0.0
    64      * @access   private
    65      * @var      boolean $hideChords Hide chords flag.
    66      */
    67     private $hideChords;
    68 
    69     /**
    70      * Hide comments flag.
    71      *
    72      * @since    1.0.0
    73      * @access   private
    74      * @var      boolean $hideComments Hide comments flag.
    75      */
    76     private $hideComments;
    77 
    78     /**
    79      * Hide composer flag.
    80      *
    81      * @since    1.0.0
    82      * @access   private
    83      * @var      boolean $hideComposer Hide composer flag.
    84      */
    85     private $hideComposer;
    86 
    87     /**
    88      * Hide subtitle flag.
    89      *
    90      * @since    1.0.0
    91      * @access   private
    92      * @var      boolean $hideSubtitle Hide subtitle flag.
    93      */
    94     private $hideSubtitle;
    95 
    96     /**
    97      * Hide print button.
    98      *
    99      * @since    1.0.0
    100      * @access   private
    101      * @var      boolean $hidePrint Hide print button.
    102      */
    103     private $hidePrint;
    104 
    105     /**
    106      * Hide title flag.
    107      *
    108      * @since    1.0.0
    109      * @access   private
    110      * @var      boolean $hideTitle Hide title flag.
    111      */
    112     private $hideTitle;
    113 
    114     /**
    115      * Hide transpose button.
    116      *
    117      * @since    1.0.0
    118      * @access   private
    119      * @var      boolean $hideTranspose Hide transpose button
    120      */
    121     private $hideTranspose;
    122 
    123     /**
    124      * Show numeric transpose input.
    125      *
    126      * @since    3.6.0
    127      * @access   private
    128      * @var      boolean $showNumericTranspose Hide transpose button
    129      */
    130     private $showNumericTranspose;
    131 
    132     /**
    133      * Place interaction bar fixed at bottom of page.
    134      *
    135      * @since    3.6.0
    136      * @access   private
    137      * @var      boolean $fixedInteraction
    138      */
    139     private $fixedInteraction;
    140 
    141     /**
    142      * Hide year flag.
    143      *
    144      * @since    1.0.0
    145      * @access   private
    146      * @var      boolean $hideYear Hide year flag.
    147      */
    148     private $hideYear;
    149 
    150     /**
    151      * HTML header level for title.
    152      *
    153      * @since    1.0.0
    154      * @access   private
    155      * @var      string $titleLevel HTML header level for title.
    156      */
    157     private $titleLevel;
    158 
    159     /**
    160      * HTML header level for subtitle.
    161      *
    162      * @since    1.0.0
    163      * @access   private
    164      * @var      string $subtitleLevel HTML header level for subtitle.
    165      */
    166     private $subtitleLevel;
    167 
    168     /**
    169      * CSS styles for meta info.
    170      *
    171      * @since    1.0.0
    172      * @access   private
    173      * @var      string $metaStyle CSS styles for meta info.
    174      */
    175     private $metaStyle;
    176 
    177     /**
    178      * CSS text color for chords.
    179      *
    180      * @since    1.0.0
    181      * @access   private
    182      * @var      string $chordTextcolor CSS text color for chords.
    183      */
    184     private $chordTextcolor;
    185 
    186     /**
    187      * CSS text size for chords.
    188      *
    189      * @since    1.0.0
    190      * @access   private
    191      * @var      string $chordTextsize CSS text size for chords.
    192      */
    193     private $chordTextsize;
    194 
    195     /**
    196      * CSS text color for lyrics.
    197      *
    198      * @since    1.0.0
    199      * @access   private
    200      * @var      string $lyricsTextcolor CSS text color for lyrics.
    201      */
    202     private $lyricsTextcolor;
    203 
    204     /**
    205      * CSS text size for lyrics.
    206      *
    207      * @since    1.0.0
    208      * @access   private
    209      * @var      string $lyricsTextsize CSS text size for lyrics.
    210      */
    211     private $lyricsTextsize;
    212 
    213     /**
    214      * CSS styles for lyrics.
    215      *
    216      * @since    2.3.0
    217      * @access   private
    218      * @var      string $lyricsStyle CSS styles for lyrics.
    219      */
    220     private $lyricsStyle;
    221 
    222     /**
    223      * CSS styles for comments.
    224      *
    225      * @since    1.0.0
    226      * @access   private
    227      * @var      string $commentStyle CSS styles for comments.
    228      */
    229     private $commentStyle;
    230 
    231     /**
    232      * CSS styles for the chords.
    233      *
    234      * @since    1.0.0
    235      * @access   private
    236      * @var      string $chordStyle CSS styles for the chorus sections.
    237      */
    238     private $chordStyle;
    239 
    240     /**
    241      * CSS styles for the chorus sections.
    242      *
    243      * @since    1.0.0
    244      * @access   private
    245      * @var      string $chorusStyle CSS styles for the chorus sections.
    246      */
    247     private $chorusStyle;
    248 
    249     /**
    250      * CSS styles for the verse sections.
    251      *
    252      * @since    1.0.0
    253      * @access   private
    254      * @var      string $verseStyle CSS styles for the verse sections.
    255      */
    256     private $verseStyle;
    257 
    258     /**
    259      * CSS styles for the line sections.
    260      *
    261      * @since    3.1.2
    262      * @access   private
    263      * @var      string $lineStyle CSS styles for the line sections.
    264      */
    265     private $lineStyle;
    266 
    267     /**
    268      * CSS float directive: no/left/right.
    269      *
    270      * @since    1.5.0
    271      * @access   private
    272      * @var      string $float CSS float directive: no/left/right.
    273      */
    274     private $float;
    275 
    276     /**
    277      * Shortcode directive hbNotation: no/yes.
    278      *
    279      * @since    1.0.0
    280      * @access   private
    281      * @var      string $hbNotation Shortcode directive hbNotation: no/yes.
    282      */
    283     private $hbNotation;
    284 
    285     /**
    286      * Show Chord Sheet for Vexchords.
    287      *
    288      * @since    2.1.0
    289      * @access   private
    290      * @var      string $showChordSheet Show Chord Sheet: no/yes.
    291      */
    292     private $showChordSheet;
    293 
    294     /**
    295      * Show Chord Sheet on top.
    296      *
    297      * @since    2.1.0
    298      * @access   private
    299      * @var      string $showChordSheetOnTop Show Chord Sheet on top: no/yes.
    300      */
    301     private $showChordSheetOnTop;
    302 
    303     /**
    304      * Shortcode directive interactive: no/yes.
    305      *
    306      * @since    1.5.0
    307      * @access   private
    308      * @var      string $interactive Shortcode directive interactive: no/yes.
    309      */
    310     private $interactive;
    311 
    312     /**
    313      * Shortcode directive transpose: 0-11 (semitones).
    314      *
    315      * @since    1.0.0
    316      * @access   private
    317      * @var      string $transpose Shortcode directive transpose: 0-11 (semitones).
    318      */
    319     private $transpose;
    320 
    321     /**
    322      * Array of supported ChordPro directives.
    323      *
    324      * @since    1.0.0
    325      * @access   private
    326      * @var      array $arrDirectives Array of supported ChordPro directives.
    327      */
    328     private $arrDirectives = array(
    329         'album' => '',
    330         'artist' => '',
    331         'capo' => '',
    332         'composer' => '',
    333         'key' => '',
    334         'subtitle' => '',
    335         'tempo' => '',
    336         'time' => '',
    337         'title' => '',
    338         'year' => '',
     22class ChordPress_Renderer {
     23  /**
     24   * Guitar chord instance.
     25   *
     26   * @since    2.1.0
     27   * @access   private
     28   * @var      ChordPress_Chord $C Guitar chord instance.
     29   */
     30  private $C;
     31
     32  /**
     33   * Display H/B notation flag.
     34   *
     35   * @since    1.0.0
     36   * @access   private
     37   * @var      boolean $displayHBNotation Display H/B notation flag.
     38   */
     39  private $displayHBNotation;
     40
     41  /**
     42   * Hide album flag.
     43   *
     44   * @since    1.0.0
     45   * @access   private
     46   * @var      boolean $hideAlbum Hide album flag.
     47   */
     48  private $hideAlbum;
     49
     50  /**
     51   * Hide artist flag.
     52   *
     53   * @since    1.0.0
     54   * @access   private
     55   * @var      boolean $hideArtist Hide artist flag.
     56   */
     57  private $hideArtist;
     58
     59  /**
     60   * Hide chords flag.
     61   *
     62   * @since    1.0.0
     63   * @access   private
     64   * @var      boolean $hideChords Hide chords flag.
     65   */
     66  private $hideChords;
     67
     68  /**
     69   * Hide comments flag.
     70   *
     71   * @since    1.0.0
     72   * @access   private
     73   * @var      boolean $hideComments Hide comments flag.
     74   */
     75  private $hideComments;
     76
     77  /**
     78   * Hide composer flag.
     79   *
     80   * @since    1.0.0
     81   * @access   private
     82   * @var      boolean $hideComposer Hide composer flag.
     83   */
     84  private $hideComposer;
     85
     86  /**
     87   * Hide subtitle flag.
     88   *
     89   * @since    1.0.0
     90   * @access   private
     91   * @var      boolean $hideSubtitle Hide subtitle flag.
     92   */
     93  private $hideSubtitle;
     94
     95  /**
     96   * Hide print button.
     97   *
     98   * @since    1.0.0
     99   * @access   private
     100   * @var      boolean $hidePrint Hide print button.
     101   */
     102  private $hidePrint;
     103
     104  /**
     105   * Hide title flag.
     106   *
     107   * @since    1.0.0
     108   * @access   private
     109   * @var      boolean $hideTitle Hide title flag.
     110   */
     111  private $hideTitle;
     112
     113  /**
     114   * Hide transpose button.
     115   *
     116   * @since    1.0.0
     117   * @access   private
     118   * @var      boolean $hideTranspose Hide transpose button
     119   */
     120  private $hideTranspose;
     121
     122  /**
     123   * Show numeric transpose input.
     124   *
     125   * @since    3.6.0
     126   * @access   private
     127   * @var      boolean $showNumericTranspose Hide transpose button
     128   */
     129  private $showNumericTranspose;
     130
     131  /**
     132   * Place interaction bar fixed at bottom of page.
     133   *
     134   * @since    3.6.0
     135   * @access   private
     136   * @var      boolean $fixedInteraction
     137   */
     138  private $fixedInteraction;
     139
     140  /**
     141   * Hide year flag.
     142   *
     143   * @since    1.0.0
     144   * @access   private
     145   * @var      boolean $hideYear Hide year flag.
     146   */
     147  private $hideYear;
     148
     149  /**
     150   * HTML header level for title.
     151   *
     152   * @since    1.0.0
     153   * @access   private
     154   * @var      string $titleLevel HTML header level for title.
     155   */
     156  private $titleLevel;
     157
     158  /**
     159   * HTML header level for subtitle.
     160   *
     161   * @since    1.0.0
     162   * @access   private
     163   * @var      string $subtitleLevel HTML header level for subtitle.
     164   */
     165  private $subtitleLevel;
     166
     167  /**
     168   * CSS styles for meta info.
     169   *
     170   * @since    1.0.0
     171   * @access   private
     172   * @var      string $metaStyle CSS styles for meta info.
     173   */
     174  private $metaStyle;
     175
     176  /**
     177   * CSS text color for chords.
     178   *
     179   * @since    1.0.0
     180   * @access   private
     181   * @var      string $chordTextcolor CSS text color for chords.
     182   */
     183  private $chordTextcolor;
     184
     185  /**
     186   * CSS text size for chords.
     187   *
     188   * @since    1.0.0
     189   * @access   private
     190   * @var      string $chordTextsize CSS text size for chords.
     191   */
     192  private $chordTextsize;
     193
     194  /**
     195   * CSS text color for lyrics.
     196   *
     197   * @since    1.0.0
     198   * @access   private
     199   * @var      string $lyricsTextcolor CSS text color for lyrics.
     200   */
     201  private $lyricsTextcolor;
     202
     203  /**
     204   * CSS text size for lyrics.
     205   *
     206   * @since    1.0.0
     207   * @access   private
     208   * @var      string $lyricsTextsize CSS text size for lyrics.
     209   */
     210  private $lyricsTextsize;
     211
     212  /**
     213   * CSS styles for lyrics.
     214   *
     215   * @since    2.3.0
     216   * @access   private
     217   * @var      string $lyricsStyle CSS styles for lyrics.
     218   */
     219  private $lyricsStyle;
     220
     221  /**
     222   * CSS styles for comments.
     223   *
     224   * @since    1.0.0
     225   * @access   private
     226   * @var      string $commentStyle CSS styles for comments.
     227   */
     228  private $commentStyle;
     229
     230  /**
     231   * CSS styles for the chords.
     232   *
     233   * @since    1.0.0
     234   * @access   private
     235   * @var      string $chordStyle CSS styles for the chorus sections.
     236   */
     237  private $chordStyle;
     238
     239  /**
     240   * CSS styles for the chorus sections.
     241   *
     242   * @since    1.0.0
     243   * @access   private
     244   * @var      string $chorusStyle CSS styles for the chorus sections.
     245   */
     246  private $chorusStyle;
     247
     248  /**
     249   * CSS styles for the verse sections.
     250   *
     251   * @since    1.0.0
     252   * @access   private
     253   * @var      string $verseStyle CSS styles for the verse sections.
     254   */
     255  private $verseStyle;
     256
     257  /**
     258   * CSS styles for the line sections.
     259   *
     260   * @since    3.1.2
     261   * @access   private
     262   * @var      string $lineStyle CSS styles for the line sections.
     263   */
     264  private $lineStyle;
     265
     266  /**
     267   * CSS float directive: no/left/right.
     268   *
     269   * @since    1.5.0
     270   * @access   private
     271   * @var      string $float CSS float directive: no/left/right.
     272   */
     273  private $float;
     274
     275  /**
     276   * Shortcode directive hbNotation: no/yes.
     277   *
     278   * @since    1.0.0
     279   * @access   private
     280   * @var      string $hbNotation Shortcode directive hbNotation: no/yes.
     281   */
     282  private $hbNotation;
     283
     284  /**
     285   * Show Chord Sheet for Vexchords.
     286   *
     287   * @since    2.1.0
     288   * @access   private
     289   * @var      string $showChordSheet Show Chord Sheet: no/yes.
     290   */
     291  private $showChordSheet;
     292
     293  /**
     294   * Show Chord Sheet on top.
     295   *
     296   * @since    2.1.0
     297   * @access   private
     298   * @var      string $showChordSheetOnTop Show Chord Sheet on top: no/yes.
     299   */
     300  private $showChordSheetOnTop;
     301
     302  /**
     303   * Shortcode directive interactive: no/yes.
     304   *
     305   * @since    1.5.0
     306   * @access   private
     307   * @var      string $interactive Shortcode directive interactive: no/yes.
     308   */
     309  private $interactive;
     310
     311  /**
     312   * Shortcode directive transpose: 0-11 (semitones).
     313   *
     314   * @since    1.0.0
     315   * @access   private
     316   * @var      string $transpose Shortcode directive transpose: 0-11 (semitones).
     317   */
     318  private $transpose;
     319
     320  /**
     321   * Array of supported ChordPro directives.
     322   *
     323   * @since    1.0.0
     324   * @access   private
     325   * @var      array $arrDirectives Array of supported ChordPro directives.
     326   */
     327  private $arrDirectives = array(
     328    'album' => '',
     329    'artist' => '',
     330    'capo' => '',
     331    'composer' => '',
     332    'key' => '',
     333    'subtitle' => '',
     334    'tempo' => '',
     335    'time' => '',
     336    'title' => '',
     337    'year' => '',
     338  );
     339
     340  /**
     341   * Array of all chords in this song.
     342   *
     343   * @since    2.1.0
     344   * @access   private
     345   * @var      array $allChords Array of all chords in this song.
     346   */
     347  private $allChords = array();
     348
     349  /**
     350   * Array of unique chords in this song.
     351   *
     352   * @since    2.1.0
     353   * @access   private
     354   * @var      array $uniqueChords Array of unique chords in this song.
     355   */
     356  private $uniqueChords = array();
     357
     358  /**
     359   * Array of supported Key directives.
     360   *
     361   * @since    3.1.0
     362   * @access   private
     363   * @var      array
     364   */
     365  private $arrKeys = array( 'A', 'Am', 'A#', 'A#m', 'Bb', 'Bbm', 'B', 'Bm', 'C', 'Cm', 'C#', 'C#m', 'Db', 'Dbm', 'D', 'Dm', 'D#', 'D#m', 'Eb', 'Ebm', 'E', 'Em', 'F', 'Fm', 'G', 'Gm', 'G#', 'G#m', 'Ab', 'Abm' );
     366
     367  /**
     368   * Array of transposed keys.
     369   *
     370   * @since    3.1.0
     371   * @access   private
     372   * @var      array
     373   */
     374  private $arrTransposeValues = array(
     375    'A' => array( 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#' ),
     376    'Am' => array( 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m' ),
     377    'A#' => array( 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A' ),
     378    'Bb' => array( 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A' ),
     379    'A#m' => array( 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am' ),
     380    'Bbm' => array( 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am' ),
     381    'B' => array( 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#' ),
     382    'Bm' => array( 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m' ),
     383    'C' => array( 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B' ),
     384    'Cm' => array( 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm' ),
     385    'C#' => array( 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C' ),
     386    'Db' => array( 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C' ),
     387    'C#m' => array( 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm' ),
     388    'Dbm' => array( 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm' ),
     389    'D' => array( 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#' ),
     390    'Dm' => array( 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m' ),
     391    'D#' => array( 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D' ),
     392    'Eb' => array( 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D' ),
     393    'D#m' => array( 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm' ),
     394    'Ebm' => array( 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm' ),
     395    'E' => array( 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#' ),
     396    'Em' => array( 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m' ),
     397    'F' => array( 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E' ),
     398    'Fm' => array( 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em' ),
     399    'F#' => array( 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F' ),
     400    'Gb' => array( 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F' ),
     401    'F#m' => array( 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm' ),
     402    'Gbm' => array( 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm' ),
     403    'G' => array( 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#' ),
     404    'Gm' => array( 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m' ),
     405    'G#' => array( 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G' ),
     406    'Ab' => array( 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G' ),
     407    'G#m' => array( 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm' ),
     408    'Abm' => array( 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm' ),
     409  );
     410
     411  /**
     412   * In monospace mode.
     413   * As long as true, lines are not analyzed, just printed out.
     414   *
     415   * @since    3.5.0
     416   * @access   private
     417   * @var      boolean $inMonospace Monospace mode flag.
     418   */
     419  private $inMonospace;
     420
     421  /**
     422   * Array of allowed prefixes for chords.
     423   *
     424   * @since    3.6.1
     425   * @access   private
     426   * @var      array
     427   */
     428  private $allowedChordPrefixes = array( '~', '|', '/', '.', '-' );
     429
     430
     431  //---------------------------------------------------------------------------
     432  /**
     433   * Initialize the class and set its properties.
     434   *
     435   * @since    1.0.0
     436   */
     437  public function __construct() {
     438    $this->C = new ChordPress_Chord();
     439    /**
     440     * Shortcode Defaults
     441     */
     442    $this->float = 'no';
     443    $this->hbNotation = 'no';
     444    $this->interactive = 'no';
     445    $this->transpose = 0;
     446    /**
     447     * Get options or set defaults
     448     */
     449    if (!$this->hideAlbum = get_option('chordpress_checkbox_hide_album')) $this->hideAlbum = 0;
     450    if (!$this->hideArtist = get_option('chordpress_checkbox_hide_artist')) $this->hideArtist = 0;
     451    if (!$this->hideChords = get_option('chordpress_checkbox_hide_chords')) $this->hideChords = 0;
     452    if (!$this->hideComments = get_option('chordpress_checkbox_hide_comments')) $this->hideComments = 0;
     453    if (!$this->hideComposer = get_option('chordpress_checkbox_hide_composer')) $this->hideComposer = 0;
     454    if (!$this->hidePrint = get_option('chordpress_checkbox_hide_print')) $this->hidePrint = 0;
     455    if (!$this->hideSubtitle = get_option('chordpress_checkbox_hide_subtitle')) $this->hideSubtitle = 0;
     456    if (!$this->hideTitle = get_option('chordpress_checkbox_hide_title')) $this->hideTitle = 0;
     457    if (!$this->hideTranspose = get_option('chordpress_checkbox_hide_transpose')) $this->hideTranspose = 0;
     458    if (!$this->hideYear = get_option('chordpress_checkbox_hide_year')) $this->hideYear = 0;
     459    if (!$this->displayHBNotation = get_option('chordpress_checkbox_hb_notation')) $this->displayHBNotation = 0;
     460    if (!$this->showChordSheet = get_option('chordpress_checkbox_show_chord_sheet')) $this->showChordSheet = 0;
     461    if (!$this->showChordSheetOnTop = get_option('chordpress_checkbox_show_chord_sheet_on_top')) $this->showChordSheetOnTop = 0;
     462    if (!$this->showNumericTranspose = get_option('chordpress_checkbox_show_numeric_transpose')) $this->showNumericTranspose = 0;
     463    if (!$this->fixedInteraction = get_option('chordpress_checkbox_fixed_interaction')) $this->fixedInteraction = 0;
     464
     465    if (!$this->titleLevel = get_option('chordpress_select_title_level')) $this->titleLevel = 'h1';
     466    if (!$this->subtitleLevel = get_option('chordpress_select_subtitle_level')) $this->subtitleLevel = 'h2';
     467    if (!$this->metaStyle = get_option('chordpress_text_meta_style')) $this->metaStyle = '';
     468    if (!$this->chordStyle = get_option('chordpress_text_chord_style')) $this->chordStyle = '';
     469    if (!$this->lyricsStyle = get_option('chordpress_text_lyrics_style')) $this->lyricsStyle = '';
     470    if (!$this->commentStyle = get_option('chordpress_text_comment_style')) $this->commentStyle = '';
     471    if (!$this->chorusStyle = get_option('chordpress_text_chorus_style')) $this->chorusStyle = '';
     472    if (!$this->verseStyle = get_option('chordpress_text_verse_style')) $this->verseStyle = '';
     473    if (!$this->lineStyle = get_option('chordpress_text_line_style')) $this->lineStyle = 'margin: 1em 0 1em 0;';
     474  }
     475
     476  //---------------------------------------------------------------------------
     477  /**
     478   * Get the ChordPro directives and store the supported ones in an array.
     479   *
     480   * @param object $text - Text inside shortcode wrapper.
     481   * @since 1.0.0
     482   */
     483  public function getDirectives($text) {
     484    foreach ($text as $line) {
     485      $line = trim($this->stripTags($line));
     486      if (strlen($line) && $line[0] == '{') {
     487        /**
     488         * Line starts with "{": It's a directive
     489         * Get directive name and value and store
     490         */
     491        $arrDirective = explode(":", $line);
     492        // $this->pretty_dump($arrDirective);
     493        $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
     494        if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
     495        /**
     496         * Process directive alternatives
     497         */
     498        switch (strtolower($directiveName)) {
     499          case "t":
     500            $directiveName = 'title';
     501            break;
     502          case "st":
     503            $directiveName = 'subtitle';
     504            break;
     505          case "meta":
     506            /**
     507             * {meta: title Heart of Gold}
     508             * We have split the "meta:" off already.
     509             * Now comes the part after.
     510             * We only handle the supported directives ($this->arrDirectives)
     511             */
     512            $arrMetaDirective = explode(" ", $directiveValue, 2);
     513            foreach ($this->arrDirectives as $key => $value) {
     514              if (trim($arrMetaDirective[0]) == $key) {
     515                $directiveName = $key;
     516                $directiveValue = trim($arrMetaDirective[1]);
     517              }
     518            }
     519            break;
     520        }
     521        /**
     522         * Store directive in directives array for later use
     523         */
     524        if (array_key_exists($directiveName, $this->arrDirectives)) {
     525          $this->arrDirectives[$directiveName] = $directiveValue;
     526        }
     527      }
     528    }
     529  }
     530
     531  //---------------------------------------------------------------------------
     532  /**
     533   * Creates the formatted HTML of the ChordPro text.
     534   *
     535   * HTML Structure
     536   *
     537   * <div class="cpress">
     538   *    <h1>{title}</h1>
     539   *    <h2>{subtitle}</h2>
     540   *    <h3>
     541   *       Album: {album}
     542   *       Artist: {artist}<br>
     543   *       Composer: {composer}<br>
     544   *       Year: {year}
     545   *    </h3>
     546   *    <div class="cpress-chorus/verse">
     547   *       <div class="cpress-line">
     548   *          <div class="cpress-line-section">
     549   *             <div class="chord">C#</div>
     550   *             <div class="lyric">Lyrics</div>
     551   *          </div>
     552   *          ...
     553   *       </div>
     554   *       ...
     555   *    </div>
     556   * </div>
     557   *
     558   * @param object $text - Text inside shortcode wrapper.
     559   * @return string - Formatted HTML of the ChordPro text.
     560   * @since 1.0.0
     561   */
     562  public function displayText($text): string {
     563    /**
     564     * Start of ChordPress wrapper
     565     */
     566    $returnText = "\n\n
     567      <!--begin: ChordPress SongSheet -->
     568      <div>
     569        <style>
     570          div.cpress { float: " . $this->float . "; }
     571          div.cpress_line { " . $this->lineStyle . "; }
     572          div.cpress_line_section { display: inline; float: left; }
     573          div.cpress_line_section .chord .chordshort { " . $this->chordStyle . "; }
     574          div.cpress_line_section .lyric { " . $this->lyricsStyle . "; }
     575          div.cpress_chorus { " . $this->chorusStyle . "; }
     576          div.cpress_verse { " . $this->verseStyle . "; }
     577          div.cpress_clear { clear: both; }
     578          div.cpress_meta { " . $this->metaStyle . "; }
     579          div.cpress_interaction { float: right; }
     580          div.cpress_interaction select { width: auto; }
     581          span.cpress_comment { " . $this->commentStyle . "; }
     582          div.cpress_chordsheet { text-align: center; }
     583        </style>
     584      </div>\n";
     585
     586    /**
     587     * Interaction menu
     588     */
     589    if (in_array(strtolower($this->interactive), array( "yes", "1", "true" ))) {
     590      $interactionForm = "<div class=\"cpress-interaction cpress-row";
     591      if ($this->fixedInteraction) {
     592        $interactionForm .= " fixed";
     593      }
     594      $interactionForm .= "\">";
     595      $interactionForm .= "<div class='cpress-col cpress-pl-0'>" . __('Font', 'chordpress') . "
     596          <div class='cpress-btn-group' role='group'>
     597            <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', -5);\">-</button>
     598            <button id=\"btnFontSize-%cpressID%\"  type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 0);\">100%</button>
     599            <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 5);\">+</button>
     600          </div>
     601        </div>";
     602      if (!$this->hideTranspose) {
     603        $interactionForm .= "<div class='cpress-col cpress-text-center' style='display: inline-block;'>";
     604        if ($this->showNumericTranspose) {
     605          $interactionForm .= "<span class=''>" . __('Transpose', 'chordpress') . "</span>
     606            <div class='cpress-btn-group' role='group'>
     607              <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'down');\">-</button>
     608              <button id=\"btnTranspose-%cpressID%\" type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'reset');\" value='0'>0</button>
     609              <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'up');\">+</button>
     610            </div>";
     611        } else {
     612          //
     613          // Let's see if a 'Key' directive was given. If so, we can add
     614          // the transposed keys to the list.
     615          //
     616          if (strlen($this->arrDirectives['key']) && in_array($this->arrDirectives['key'], $this->arrKeys)) {
     617            $i = 0;
     618            foreach ($this->arrTransposeValues[$this->arrDirectives['key']] as $val) {
     619              $tvalues[] = (string)$i . ' => ' . $val;
     620              $i++;
     621            }
     622          } else {
     623            $tvalues = array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11' );
     624          }
     625          $interactionForm .= __('Transpose', 'chordpress') . "
     626            <select class=\"cpress-form-control cpress-form-control-sm cpress-w-50 cpress-py-0 cpress-px-2 float-right\" id=\"selTranspose-%cpressID%\" onchange=\"transposeChords('%cpressID%', 'selTranspose-');return false;\" title=\"" . __('Only works for international key names', 'chordpress') . ".\">
     627              <option value=\"0\">" . $tvalues[0] . "</option>
     628              <option value=\"1\">" . $tvalues[1] . "</option>
     629              <option value=\"2\">" . $tvalues[2] . "</option>
     630              <option value=\"3\">" . $tvalues[3] . "</option>
     631              <option value=\"4\">" . $tvalues[4] . "</option>
     632              <option value=\"5\">" . $tvalues[5] . "</option>
     633              <option value=\"6\">" . $tvalues[6] . "</option>
     634              <option value=\"7\">" . $tvalues[7] . "</option>
     635              <option value=\"8\">" . $tvalues[8] . "</option>
     636              <option value=\"9\">" . $tvalues[9] . "</option>
     637              <option value=\"10\">" . $tvalues[10] . "</option>
     638              <option value=\"11\">" . $tvalues[11] . "</option>
     639            </select>";
     640        }
     641        $interactionForm .= "</div>";
     642      }
     643      $interactionForm .= "<div class='cpress-col cpress-text-end cpress-pr-0'>";
     644      if (!$this->hidePrint) {
     645        $interactionForm .= "<button class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"window.print();\">" . __('Print', 'chordpress') . "</button>\n";
     646      }
     647      $interactionForm .= "</div>";
     648      $returnText .= $interactionForm . "</div>\n";
     649    }
     650
     651    $returnText .= "<div id=\"%cpressID%\" class=\"cpress\">\n";
     652
     653    /**
     654     * Print header if directives exist
     655     */
     656    $randId = $this->random_string(true);
     657    if (strlen($this->arrDirectives['title']) && !$this->hideTitle) {
     658      $cpressID = str_replace(' ', '-', strtolower(trim($this->arrDirectives['title']))) . '-' . $randId;
     659      $returnText = str_replace('%cpressID%', $cpressID, $returnText);
     660      $returnText .= '<' . $this->titleLevel . '>' . $this->arrDirectives['title'] . '</' . $this->titleLevel . ">\n";
     661    } else {
     662      $cpressID = 'ccpress-id-' . $randId;
     663      $returnText = str_replace('%cpressID%', $cpressID, $returnText);
     664    }
     665
     666    if (strlen($this->arrDirectives['subtitle']) && !$this->hideSubtitle) {
     667      $returnText .= '<' . $this->subtitleLevel . '>' . $this->arrDirectives['subtitle'] . '</' . $this->subtitleLevel . ">\n";
     668    }
     669
     670    if (
     671      strlen($this->arrDirectives['album']) ||
     672      strlen($this->arrDirectives['artist']) ||
     673      strlen($this->arrDirectives['capo']) ||
     674      strlen($this->arrDirectives['composer']) ||
     675      strlen($this->arrDirectives['key']) ||
     676      strlen($this->arrDirectives['tempo']) ||
     677      strlen($this->arrDirectives['time']) ||
     678      strlen($this->arrDirectives['year'])
     679    ) {
     680      $returnText .= "<div class=\"cpress_meta\">\n";
     681      if (strlen($this->arrDirectives['composer']) && !$this->hideComposer) $returnText .= esc_html(__('Composer', 'chordpress')) . ': ' . $this->arrDirectives['composer'] . "<br>\n";
     682      if (strlen($this->arrDirectives['artist']) && !$this->hideArtist) $returnText .= esc_html(__('Artist', 'chordpress')) . ': ' . $this->arrDirectives['artist'] . "<br>\n";
     683      if (strlen($this->arrDirectives['year']) && !$this->hideYear) $returnText .= esc_html(__('Year', 'chordpress')) . ': ' . $this->arrDirectives['year'] . "<br>\n";
     684      if (strlen($this->arrDirectives['album']) && !$this->hideAlbum) $returnText .= esc_html(__('Album', 'chordpress')) . ': ' . $this->arrDirectives['album'] . "<br>\n";
     685
     686      if (strlen($this->arrDirectives['key'])) {
     687        $returnText .= esc_html(__('Key (original)', 'chordpress')) . ': ' . $this->arrDirectives['key'] . "<br>\n";
     688        $returnText .= esc_html(__('Key (transposed)', 'chordpress')) . ': <span class="chord-hidable-%cpressID% key-%cpressID%-0">' . $this->arrDirectives['key'] . '</span>';
     689        for ($t = 1; $t <= 11; $t++) {
     690          $returnText .= '<span class="chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none">' . $this->arrTransposeValues[$this->arrDirectives['key']][$t] . '</span>';
     691        }
     692        $returnText .= "<br>\n";
     693      }
     694
     695      if (strlen($this->arrDirectives['time'])) $returnText .= esc_html(__('Time', 'chordpress')) . ': ' . $this->arrDirectives['time'] . "<br>\n";
     696      if (strlen($this->arrDirectives['tempo'])) $returnText .= esc_html(__('Tempo', 'chordpress')) . ': ' . $this->arrDirectives['tempo'] . "<br>\n";
     697      if (strlen($this->arrDirectives['capo'])) $returnText .= esc_html(__('Capo', 'chordpress')) . ': ' . $this->arrDirectives['capo'] . "<br>\n";
     698      $returnText = preg_replace('/<br>$/', '', $returnText); // Remove last <br>
     699      $returnText .= "</div>\n";
     700    }
     701
     702    /**
     703     * Go through each line and process it
     704     */
     705    $this->inMonospace = false;
     706//        $this->C->dnd($text, false);
     707    foreach ($text as $line) {
     708      if ($this->inMonospace && strpos($line, "{end_of_monospace}") === false) {
     709        $returnText .= $line;
     710      } else {
     711//                $this->C->dnd("IN: " . $line, false);
     712        $returnText .= $this->formatAndDisplayLine($line);
     713//                $this->C->dnd("OUT: " . $returnText, false);
     714      }
     715    }
     716    $returnText = str_replace('%cpressID%', $cpressID, $returnText);
     717//        $this->C->dnd($returnText, false);
     718
     719    /**
     720     * End of ChordPress song
     721     */
     722    $returnText .= "</div>\n<!--end: ChordPress SongSheet-->\n";
     723
     724    /**
     725     * Build chord sheet if option set to true.
     726     */
     727    if ($this->showChordSheet) {
     728      $chordSheetText = "\n<!--begin: ChordPress ChordSheet-->\n";
     729      $chordSheetText .= "<div class='cpress_chordsheet'>\n";
     730      $chordSheetText .= "<div><hr></div>\n";
     731      $chordSheetText .= "<p><i>" . esc_html(__('These known chords are used in this song', 'chordpress')) . ".</i></p>";
     732      $this->uniqueChords = array_unique($this->allChords);
     733      foreach ($this->uniqueChords as $uc) {
     734        if ($postid = $this->find_guitar_chord_post($uc)) {
     735          $this->load_guitar_chord($postid);
     736          $chordSheetText .= $this->C->createSvgChord(true);
     737        }
     738      }
     739      $chordSheetText .= "</div>\n<div style=\"clear:both; padding: 16px 0 16px 0;\"><hr></div>\n<!--end: ChordPress ChordSheet-->\n\n";
     740      if ($this->showChordSheetOnTop) {
     741        $returnText = $chordSheetText . $returnText;
     742      } else {
     743        $returnText = $returnText . $chordSheetText;
     744      }
     745    }
     746
     747    // $this->C->dnd($returnText);
     748    return $returnText . "\n\n";
     749  }
     750
     751  //---------------------------------------------------------------------------
     752  /**
     753   * Process a single of the ChordPro text and return the formatted HTML.
     754   *
     755   * @param string $line - Single line from inside shortcode wrapper.
     756   * @return string - Formatted HTML.
     757   * @since 1.0.0
     758   */
     759  public function formatAndDisplayLine($line) {
     760    $returnText = "";
     761
     762    /**
     763     * Array of chords
     764     */
     765    $arrChords = array();
     766
     767    /**
     768     * Array of corresponding lyrics starting at a chord and ending prior
     769     * to the next chord or the end-of-line.
     770     */
     771    $arrLyrics = array();
     772
     773    /**
     774     * Now check what this line is all about
     775     */
     776    if (substr_count($line, "[") == 0) {
     777      /**
     778       * No chords on this line
     779       */
     780      if (isset($line[0]) && ($line[0] == '#' || $line == '<br />')) {
     781        /**
     782         * Line starts with "#": It's a comment line => return empty string
     783         */
     784        return "";
     785      } else if ((isset($line[0]) && $line[0] == '{') || (isset($line[0]) && strpos($line, '{'))) {
     786        /**
     787         * Line starts with "{" or has one in it: It's a directive
     788         * Some of them need consideration for the output
     789         */
     790        $directive = strstr($line, '{'); // Remove all before the {
     791        $arrDirective = explode(":", $directive);
     792        $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
     793        if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
     794
     795        /**
     796         * In case the directive had no colon and value, $directiveName will
     797         * still contain the trailing }. So let's remove that.
     798         */
     799        if (substr_count($directiveName, "}")) $directiveName = str_replace("}", "", $directiveName);
     800
     801        if (strpos($directiveName, 'start_of_verse') !== false) {
     802          return "<div class=\"cpress_verse\">\n<div class=\"cpress_line\">\n";
     803        } elseif (strpos($directiveName, 'end_of_verse') !== false) {
     804          return "</div></div>\n";
     805        } elseif (strpos($directiveName, 'start_of_chorus') !== false) {
     806          return "<div class=\"cpress_chorus\">\n<div class=\"cpress_line\">\n";
     807        } elseif (strpos($directiveName, 'end_of_chorus') !== false) {
     808          return "</div></div>\n";
     809        } elseif (strpos($directiveName, 'start_of_monospace') !== false) {
     810          $this->inMonospace = true;
     811          return "<pre>\n";
     812        } elseif (strpos($directiveName, 'end_of_monospace') !== false) {
     813          $this->inMonospace = false;
     814          return "</pre>\n";
     815        } elseif (
     816          strpos($directiveName, 'title') !== false ||
     817          strpos($directiveName, 'subtitle') !== false ||
     818          strpos($directiveName, 'album') !== false ||
     819          strpos($directiveName, 'artist') !== false ||
     820          strpos($directiveName, 'capo') !== false ||
     821          strpos($directiveName, 'composer') !== false ||
     822          strpos($directiveName, 'key') !== false ||
     823          strpos($directiveName, 'tempo') !== false ||
     824          strpos($directiveName, 'time') !== false ||
     825          strpos($directiveName, 'year') !== false ||
     826          strpos($directiveName, 'artist') !== false
     827        ) {
     828          //
     829          // We have already processed these directives. Just return empty for this line.
     830          //
     831          return "";
     832        } elseif (strpos($directiveName, 'comment') !== false && !$this->hideComments) {
     833          $arrLyrics[] = '<span class="cpress_comment">' . $directiveValue . '</span>';
     834        }
     835      } else {
     836        /**
     837         * Just lyrics without chords => print it
     838         */
     839        $arrLyrics[] = $line;
     840      }
     841    } elseif (substr_count($line, "[") != substr_count($line, "]")) {
     842      /**
     843       * Square bracket missing in this line
     844       */
     845      $arrLyrics[] = '<span style="color:#FF0000;"><i>' . esc_html(__('Missing square bracket in line', 'chordpress')) . ':</i></span> <code>' . $line . "</code>";
     846    } else {
     847      /**
     848       * Chords found. Split the line into segments beginning with '['
     849       */
     850      $arrBracketSegments = explode("[", $line);
     851      foreach ($arrBracketSegments as $segment) {
     852        if (strlen($segment)) {
     853          $pad = ($segment[strlen($segment) - 1] == ' ') ? '&nbsp;' : '';
     854          /**
     855           * Does the first segment start before the 1st '['?
     856           */
     857          if (substr_count($segment, "]") == 0) {
     858            $arrChords[] = " ";
     859            $arrLyrics[] = $segment . $pad;
     860          } else {
     861            /**
     862             * Split this segment into chord an lyrics
     863             */
     864            $arrChordLyric = explode("]", $segment);
     865            $arrChords[] = trim($arrChordLyric[0]);
     866            $arrLyrics[] = $arrChordLyric[1] . $pad;
     867          }
     868        }
     869      }
     870    }
     871
     872    /**
     873     * Start of line wrapper (lyrics and chords)
     874     */
     875    $returnText .= "<div class=\"cpress_line\">\n";
     876
     877    /**
     878     * Align chords and lyrics together by wrapping each in a floating inline div
     879     */
     880    if (!$this->hideChords) {
     881
     882      for ($i = 0; $i < count($arrChords); $i++) {
     883
     884        if (strlen(trim($arrChords[$i])) > 0 || strlen(trim($arrLyrics[$i])) > 0) {
     885
     886          $lyrics = trim($this->stripTags($arrLyrics[$i]));
     887
     888          /**
     889           * Start of line-section (one chord and its lyrics)
     890           */
     891          $returnText .= "<div class=\"cpress_line_section\">\n";
     892
     893          if (strlen(trim($arrChords[$i])) > 0) {
     894
     895            $returnText .= "<div class=\"chord chord-hidable-%cpressID% key-%cpressID%-0\"><span class=\"chordshort\">";
     896
     897            /**
     898             * Allow chords starting with a ~, |, / and . as chord placeholders. Just return the string.
     899             * Att: ... will end up as &ellip; . Use blanks between each dot.
     900             */
     901            if (in_array($arrChords[$i][0], $this->allowedChordPrefixes)) {
     902              $returnText .= $arrChords[$i];
     903            } else {
     904              $theChord = $this->formatChord($arrChords[$i]);
     905              $this->allChords[] = $theChord;
     906              $returnText .= $theChord;
     907            }
     908
     909            $returnText .= "</span>&nbsp;</div>\n";
     910
     911            /**
     912             * Prepare all other 11 transposed versions of the chord
     913             * but hide them. They need to be on the page for interactive
     914             * mode to show/hide them via Javascript.
     915             * But do not mark empty chord divs as hidable. They need to stay.
     916             */
     917            $returnText .= "\n";
     918            $tempTranspose = $this->getTranspose();
     919
     920            for ($t = 1; $t <= 11; $t++) {
     921              $this->setTranspose($t);
     922              /**
     923               * Allow chords starting with a special characters, e.g. ~ as chord placeholders.
     924               * Just return the string.
     925               */
     926              if (in_array($arrChords[$i][0], $this->allowedChordPrefixes)) {
     927                $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $arrChords[$i] . '</span>&nbsp;</div>';
     928                $returnText .= "\n";
     929              } else {
     930                /**
     931                 * This is a real chord.
     932                 */
     933                $theChord = $this->formatChord($arrChords[$i]);
     934                $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $theChord . '</span>&nbsp;</div>';
     935              }
     936            }
     937
     938            $this->setTranspose($tempTranspose);
     939
     940            /**
     941             * Now add the lyrics for this section.
     942             */
     943            $returnText .= '<div class="lyric">';
     944
     945            if (strlen($lyrics) > 0) {
     946              $endOf1stWord = strpos($lyrics, ' ');
     947              $numSpaces = substr_count($lyrics, ' ');
     948              if ($endOf1stWord > 0 && $numSpaces == 1) {
     949                $returnText .= substr($lyrics, 0, $endOf1stWord) . '&nbsp;';
     950                $lyrics = substr($lyrics, $endOf1stWord);
     951                $returnText .= "</div></div>\n<div class=\"cpress_line_section\">\n<div class=\"chord\">&nbsp;</div><div class=\"lyric\">";
     952              }
     953            }
     954          } else {
     955            $returnText .= '<div class="chord">&nbsp;</div>';
     956            $returnText .= '<div class="lyric">';
     957          }
     958
     959          if (strlen($lyrics) > 0) $returnText .= $lyrics;
     960          $returnText .= "</div>\n"; // end of lyric
     961          $returnText .= "</div>\n"; // end of line
     962
     963        }
     964      }
     965
     966      /**
     967       * If there are more lyric parts than chord parts, add them here
     968       */
     969      for ($i = count($arrChords); $i < count($arrLyrics); $i++) {
     970        $returnText .= $arrLyrics[$i];
     971      }
     972    } else {
     973
     974      /**
     975       * Hide chords was selected, so only show the lyrics
     976       */
     977      $returnText .= '<div class="cpress_line_section"><div class="lyric">';
     978
     979      for ($i = 0; $i < count($arrLyrics); $i++) {
     980        $returnText .= $arrLyrics[$i];
     981      }
     982
     983      $returnText .= "</div></div>";
     984    }
     985
     986    /**
     987     * End of line wrapper
     988     */
     989    $returnText .= "</div>\n";
     990
     991    /**
     992     * Add a clear:both div
     993     */
     994    $returnText .= "<div class='cpress_clear'></div>\n";
     995
     996    return $returnText;
     997  }
     998
     999  //---------------------------------------------------------------------------
     1000  /**
     1001   * Remove all <> wrapped text from a string.
     1002   *
     1003   * @param string $string - String to process.
     1004   * @return string - Stripped text.
     1005   * @since 1.0.0
     1006   */
     1007  private function stripTags($string) {
     1008    $retString = "";
     1009    $isVisible = true;
     1010    for ($i = 0; $i < strlen($string); $i++) {
     1011      if ($isVisible) {
     1012        if ($string[$i] == '<')
     1013          $isVisible = false;
     1014        else
     1015          $retString .= $string[$i];
     1016      } elseif ($string[$i] == '>') {
     1017        $isVisible = true;
     1018      }
     1019    }
     1020    return $retString;
     1021  }
     1022
     1023  //---------------------------------------------------------------------------
     1024  /**
     1025   * Processes a note text and returns the formatted HTML.
     1026   *
     1027   * @param string $ch - Chord text, e.g. "A" or "B#" or "Db/F" or "IV".
     1028   * @return string - Uppercase note string.
     1029   * @since 1.0.0
     1030   */
     1031  public function formatChord($ch) {
     1032    $useFlats = false;
     1033    if (strlen($ch) == 0) return '';
     1034
     1035    /**
     1036     * Return other valid chord identifiers as is
     1037     */
     1038    $italianChords = array( 'Do', 'do', 'Re', 're', 'Mi', 'mi', 'Fa', 'fa', 'Sol', 'sol', 'La', 'la', 'Si', 'si' );
     1039    $nashvilleChords = array( '1', '2', '3', '4', '5', '6', '7' );
     1040    $romanChords = array( 'I', 'I7', 'II', 'III', 'iii', 'IV', 'V', 'V7', 'VI', 'vi', 'VI7', 'vi7', 'VII' );
     1041    if (in_array($ch, $italianChords) or in_array($ch, $nashvilleChords) or in_array($ch, $romanChords)) return $ch;
     1042
     1043    /**
     1044     * The first letter should be the key note
     1045     */
     1046    $note = substr($ch, 0, 1);
     1047    $rem = substr($ch, 1);
     1048
     1049    /**
     1050     * Convert note to a number
     1051     */
     1052    $noteVal = $this->noteToNumber($note);
     1053
     1054    /**
     1055     * Check sharp/flat
     1056     */
     1057    if (strlen($rem) > 0) {
     1058      if (substr($rem, 0, 1) == '#') {
     1059        $noteVal++;
     1060        $rem = substr($rem, 1);
     1061      } elseif (strncasecmp($rem, "b", 1) == 0) {
     1062        $useFlats = true;
     1063        $noteVal--;
     1064        $rem = substr($rem, 1);
     1065      }
     1066    }
     1067
     1068    /**
     1069     * Add transpose
     1070     */
     1071    $noteVal += $this->transpose;
     1072    if ($noteVal > 11) $noteVal -= 12;
     1073    if ($noteVal < 0) $noteVal += 12;
     1074
     1075    /**
     1076     * Build note to display from numeric note value
     1077     */
     1078    $xlatedNote = $this->numberToNote($noteVal, $useFlats);
     1079    // die($this->pretty_dump($xlatedNote));
     1080
     1081    /**
     1082     * Return the chord display plus the bass note (if any)
     1083     */
     1084    return $xlatedNote . $this->formatRemainder($rem);
     1085  }
     1086
     1087  //---------------------------------------------------------------------------
     1088  /**
     1089   * Process the remainder of the given chord.
     1090   *
     1091   * @param string $remainder - Chord text starting at second char.
     1092   * @return string - Formatted remainder.
     1093   * @since 1.0.0
     1094   */
     1095  public function formatRemainder($remainder) {
     1096    $indexOfSlash = strpos($remainder, '/');
     1097    if ($indexOfSlash === false) return $remainder;
     1098
     1099    /**
     1100     * We have a slash, indicating that a bass note follows.
     1101     * Break the string into 2 parts at the slash.
     1102     * The slash will be lost, and will need to be added back later.
     1103     */
     1104    $chord = substr($remainder, 0, $indexOfSlash);
     1105    $bass = substr($remainder, $indexOfSlash + 1);
     1106
     1107    $useFlats = false;
     1108
     1109    if (strlen($bass) == 0) return $chord . "/?";
     1110
     1111    /**
     1112     * The first letter should be the bass note
     1113     */
     1114    $note = substr($bass, 0, 1);
     1115    $xlatedNote = $note;
     1116    $rem = substr($bass, 1);
     1117
     1118    /**
     1119     * Convert note to a number
     1120     */
     1121    $noteVal = $this->noteToNumber($note);
     1122
     1123    /**
     1124     * Check sharp/flat
     1125     */
     1126    if (strlen($rem) > 0) {
     1127      if (substr($rem, 0, 1) == '#') {
     1128        $noteVal++;
     1129        $rem = substr($rem, 1);
     1130      } elseif (strncasecmp($rem, "b", 1) == 0) {
     1131        $useFlats = true;
     1132        $noteVal--;
     1133        $rem = substr($rem, 1);
     1134      }
     1135    }
     1136
     1137    /**
     1138     * Add transpose
     1139     */
     1140    $noteVal += $this->transpose;
     1141    if ($noteVal > 11) $noteVal -= 12;
     1142    if ($noteVal < 0) $noteVal += 12;
     1143
     1144    /**
     1145     * Build note to display from numeric note value
     1146     */
     1147    $xlatedNote = $this->numberToNote($noteVal);
     1148
     1149    return $chord . "/" . $xlatedNote . $rem;
     1150  }
     1151
     1152  //---------------------------------------------------------------------------
     1153  /**
     1154   * Convert note to number.
     1155   *
     1156   * @param string $n - Note to convert.
     1157   * @return integer
     1158   * @since 1.0.0
     1159   */
     1160  public function noteToNumber($n) {
     1161    $regularNotation = array(
     1162      'A' => 0,
     1163      'B' => 2,
     1164      'C' => 3,
     1165      'D' => 5,
     1166      'E' => 7,
     1167      'F' => 8,
     1168      'G' => 10,
    3391169    );
    3401170
    341     /**
    342      * Array of all chords in this song.
    343      *
    344      * @since    2.1.0
    345      * @access   private
    346      * @var      array $allChords Array of all chords in this song.
    347      */
    348     private $allChords = array();
    349 
    350     /**
    351      * Array of unique chords in this song.
    352      *
    353      * @since    2.1.0
    354      * @access   private
    355      * @var      array $uniqueChords Array of unique chords in this song.
    356      */
    357     private $uniqueChords = array();
    358 
    359     /**
    360      * Array of supported Key directives.
    361      *
    362      * @since    3.1.0
    363      * @access   private
    364      * @var      array
    365      */
    366     private $arrKeys = array('A', 'Am', 'A#', 'A#m', 'Bb', 'Bbm', 'B', 'Bm', 'C', 'Cm', 'C#', 'C#m', 'Db', 'Dbm', 'D', 'Dm', 'D#', 'D#m', 'Eb', 'Ebm', 'E', 'Em', 'F', 'Fm', 'G', 'Gm', 'G#', 'G#m', 'Ab', 'Abm');
    367 
    368     /**
    369      * Array of transposed keys.
    370      *
    371      * @since    3.1.0
    372      * @access   private
    373      * @var      array
    374      */
    375     private $arrTransposeValues = array(
    376         'A' => array('A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'),
    377         'Am' => array('Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m'),
    378         'A#' => array('A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A'),
    379         'Bb' => array('Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A'),
    380         'A#m' => array('A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am'),
    381         'Bbm' => array('Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am'),
    382         'B' => array('B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#'),
    383         'Bm' => array('Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m'),
    384         'C' => array('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'),
    385         'Cm' => array('Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm'),
    386         'C#' => array('C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C'),
    387         'Db' => array('Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C'),
    388         'C#m' => array('C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm'),
    389         'Dbm' => array('Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm'),
    390         'D' => array('D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#'),
    391         'Dm' => array('Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m'),
    392         'D#' => array('D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D'),
    393         'Eb' => array('Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D'),
    394         'D#m' => array('D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm'),
    395         'Ebm' => array('Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm'),
    396         'E' => array('E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#'),
    397         'Em' => array('Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m'),
    398         'F' => array('F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E'),
    399         'Fm' => array('Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em'),
    400         'F#' => array('F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F'),
    401         'Gb' => array('Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F'),
    402         'F#m' => array('F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm'),
    403         'Gbm' => array('Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm'),
    404         'G' => array('G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#'),
    405         'Gm' => array('Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m'),
    406         'G#' => array('G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G'),
    407         'Ab' => array('Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G'),
    408         'G#m' => array('G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm'),
    409         'Abm' => array('Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm'),
     1171    $hbNotation = array(
     1172      'A' => 0,
     1173      'B' => 1,
     1174      'H' => 2,
     1175      'C' => 3,
     1176      'D' => 5,
     1177      'E' => 7,
     1178      'F' => 8,
     1179      'G' => 10,
    4101180    );
    4111181
    412     /**
    413      * In monospace mode.
    414      * As long as true, lines are not analyzed, just printed out.
    415      *
    416      * @since    3.5.0
    417      * @access   private
    418      * @var      boolean $inMonospace Monospace mode flag.
    419      */
    420     private $inMonospace;
    421 
    422     //--------------------------------------------------------------------------
    423 
    424     /**
    425      * Initialize the class and set its properties.
    426      *
    427      * @since    1.0.0
    428      */
    429     public function __construct()
    430     {
    431         $this->C = new ChordPress_Chord();
    432         /**
    433          * Shortcode Defaults
    434          */
    435         $this->float = 'no';
    436         $this->hbNotation = 'no';
    437         $this->interactive = 'no';
    438         $this->transpose = 0;
    439         /**
    440          * Get options or set defaults
    441          */
    442         if (!$this->hideAlbum = get_option('chordpress_checkbox_hide_album')) $this->hideAlbum = 0;
    443         if (!$this->hideArtist = get_option('chordpress_checkbox_hide_artist')) $this->hideArtist = 0;
    444         if (!$this->hideChords = get_option('chordpress_checkbox_hide_chords')) $this->hideChords = 0;
    445         if (!$this->hideComments = get_option('chordpress_checkbox_hide_comments')) $this->hideComments = 0;
    446         if (!$this->hideComposer = get_option('chordpress_checkbox_hide_composer')) $this->hideComposer = 0;
    447         if (!$this->hidePrint = get_option('chordpress_checkbox_hide_print')) $this->hidePrint = 0;
    448         if (!$this->hideSubtitle = get_option('chordpress_checkbox_hide_subtitle')) $this->hideSubtitle = 0;
    449         if (!$this->hideTitle = get_option('chordpress_checkbox_hide_title')) $this->hideTitle = 0;
    450         if (!$this->hideTranspose = get_option('chordpress_checkbox_hide_transpose')) $this->hideTranspose = 0;
    451         if (!$this->hideYear = get_option('chordpress_checkbox_hide_year')) $this->hideYear = 0;
    452         if (!$this->displayHBNotation = get_option('chordpress_checkbox_hb_notation')) $this->displayHBNotation = 0;
    453         if (!$this->showChordSheet = get_option('chordpress_checkbox_show_chord_sheet')) $this->showChordSheet = 0;
    454         if (!$this->showChordSheetOnTop = get_option('chordpress_checkbox_show_chord_sheet_on_top')) $this->showChordSheetOnTop = 0;
    455         if (!$this->showNumericTranspose = get_option('chordpress_checkbox_show_numeric_transpose')) $this->showNumericTranspose = 0;
    456         if (!$this->fixedInteraction = get_option('chordpress_checkbox_fixed_interaction')) $this->fixedInteraction = 0;
    457 
    458         if (!$this->titleLevel = get_option('chordpress_select_title_level')) $this->titleLevel = 'h1';
    459         if (!$this->subtitleLevel = get_option('chordpress_select_subtitle_level')) $this->subtitleLevel = 'h2';
    460         if (!$this->metaStyle = get_option('chordpress_text_meta_style')) $this->metaStyle = '';
    461         if (!$this->chordStyle = get_option('chordpress_text_chord_style')) $this->chordStyle = '';
    462         if (!$this->lyricsStyle = get_option('chordpress_text_lyrics_style')) $this->lyricsStyle = '';
    463         if (!$this->commentStyle = get_option('chordpress_text_comment_style')) $this->commentStyle = '';
    464         if (!$this->chorusStyle = get_option('chordpress_text_chorus_style')) $this->chorusStyle = '';
    465         if (!$this->verseStyle = get_option('chordpress_text_verse_style')) $this->verseStyle = '';
    466         if (!$this->lineStyle = get_option('chordpress_text_line_style')) $this->lineStyle = 'margin: 1em 0 1em 0;';
    467     }
    468 
    469     //--------------------------------------------------------------------------
    470 
    471     /**
    472      * Get the ChordPro directives and store the supported ones in an array.
    473      *
    474      * @param object $text - Text inside shortcode wrapper.
    475      * @since 1.0.0
    476      */
    477     public function getDirectives($text)
    478     {
    479         foreach ($text as $line) {
    480             $line = trim($this->stripTags($line));
    481             if (strlen($line) && $line[0] == '{') {
    482                 /**
    483                  * Line starts with "{": It's a directive
    484                  * Get directive name and value and store
    485                  */
    486                 $arrDirective = explode(":", $line);
    487                 // $this->pretty_dump($arrDirective);
    488                 $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
    489                 if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
    490                 /**
    491                  * Process directive alternatives
    492                  */
    493                 switch (strtolower($directiveName)) {
    494                     case "t":
    495                         $directiveName = 'title';
    496                         break;
    497                     case "st":
    498                         $directiveName = 'subtitle';
    499                         break;
    500                     case "meta":
    501                         /**
    502                          * {meta: title Heart of Gold}
    503                          * We have split the "meta:" off already.
    504                          * Now comes the part after.
    505                          * We only handle the supported directives ($this->arrDirectives)
    506                          */
    507                         $arrMetaDirective = explode(" ", $directiveValue, 2);
    508                         foreach ($this->arrDirectives as $key => $value) {
    509                             if (trim($arrMetaDirective[0]) == $key) {
    510                                 $directiveName = $key;
    511                                 $directiveValue = trim($arrMetaDirective[1]);
    512                             }
    513                         }
    514                         break;
    515                 }
    516                 /**
    517                  * Store directive in directives array for later use
    518                  */
    519                 if (array_key_exists($directiveName, $this->arrDirectives)) {
    520                     $this->arrDirectives[$directiveName] = $directiveValue;
    521                 }
    522             }
     1182    if (in_array(strtolower($this->hbNotation), array( "yes", "1", "true" ))) {
     1183      if (array_key_exists(strtoupper($n), $hbNotation)) {
     1184        return $hbNotation[strtoupper($n)];
     1185      } else {
     1186        return 0;
     1187      }
     1188    } else {
     1189      if (array_key_exists(strtoupper($n), $regularNotation)) {
     1190        return $regularNotation[strtoupper($n)];
     1191      } else {
     1192        return 0;
     1193      }
     1194    }
     1195  }
     1196
     1197  //---------------------------------------------------------------------------
     1198  /**
     1199   * Convert number to note.
     1200   *
     1201   * @param integer $n - Numeric note value to convert to note string.
     1202   * @param boolean $useFlats - Whether to use flat notes or not.
     1203   * @return string
     1204   * @since 1.0.0
     1205   */
     1206  public function numberToNote($n, $useFlats = false) {
     1207    $retVal = '';
     1208
     1209    switch ($n) {
     1210      case 0:
     1211        $retVal = 'A';
     1212        break;
     1213      case 1:
     1214        if ($this->displayHBNotation) {
     1215          $retVal = 'B';
     1216        } else {
     1217          if ($useFlats) $retVal = "Bb";
     1218          else $retVal = "A#";
    5231219        }
    524     }
    525 
    526     //--------------------------------------------------------------------------
    527 
    528     /**
    529      * Creates the formatted HTML of the ChordPro text.
    530      *
    531      * HTML Structure
    532      *
    533      * <div class="cpress">
    534      *    <h1>{title}</h1>
    535      *    <h2>{subtitle}</h2>
    536      *    <h3>
    537      *       Album: {album}
    538      *       Artist: {artist}<br>
    539      *       Composer: {composer}<br>
    540      *       Year: {year}
    541      *    </h3>
    542      *    <div class="cpress-chorus/verse">
    543      *       <div class="cpress-line">
    544      *          <div class="cpress-line-section">
    545      *             <div class="chord">C#</div>
    546      *             <div class="lyric">Lyrics</div>
    547      *          </div>
    548      *          ...
    549      *       </div>
    550      *       ...
    551      *    </div>
    552      * </div>
    553      *
    554      * @param object $text - Text inside shortcode wrapper.
    555      * @return string - Formatted HTML of the ChordPro text.
    556      * @since 1.0.0
    557      */
    558     public function displayText($text): string
    559     {
    560         /**
    561          * Start of ChordPress wrapper
    562          */
    563         $returnText = "\n\n
    564         <!--begin: ChordPress SongSheet -->
    565         <div>
    566             <style>
    567                 div.cpress { float: " . $this->float . "; }
    568                 div.cpress_line { " . $this->lineStyle . "; }
    569                 div.cpress_line_section { display: inline; float: left; }
    570                 div.cpress_line_section .chord .chordshort { " . $this->chordStyle . "; }
    571                 div.cpress_line_section .lyric { " . $this->lyricsStyle . "; }
    572                 div.cpress_chorus { " . $this->chorusStyle . "; }
    573                 div.cpress_verse { " . $this->verseStyle . "; }
    574                 div.cpress_clear { clear: both; }
    575                 div.cpress_meta { " . $this->metaStyle . "; }
    576                 div.cpress_interaction { float: right; }
    577                 div.cpress_interaction select { width: auto; }
    578                 span.cpress_comment { " . $this->commentStyle . "; }
    579                 div.cpress_chordsheet { text-align: center; }
    580             </style>
    581         </div>\n";
    582 
    583         /**
    584          * Interaction menu
    585          */
    586         if (in_array(strtolower($this->interactive), array("yes", "1", "true"))) {
    587             $interactionForm = "<div class=\"cpress-interaction cpress-row";
    588             if ($this->fixedInteraction) {
    589                 $interactionForm .= " fixed";
    590             }
    591             $interactionForm .= "\">";
    592             $interactionForm .= "<div class='cpress-col cpress-pl-0'>" . __('Font', 'chordpress') . "
    593               <div class='cpress-btn-group' role='group'>
    594                 <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', -5);\">-</button>
    595                 <button id=\"btnFontSize-%cpressID%\"  type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 0);\">100%</button>
    596                 <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 5);\">+</button>
    597               </div>
    598             </div>";
    599             if (!$this->hideTranspose) {
    600                 $interactionForm .= "<div class='cpress-col cpress-text-center' style='display: inline-block;'>";
    601                 if ($this->showNumericTranspose) {
    602                     $interactionForm .= "<span class=''>" . __('Transpose', 'chordpress') . "</span>
    603                       <div class='cpress-btn-group' role='group'>
    604                         <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'down');\">-</button>
    605                         <button id=\"btnTranspose-%cpressID%\" type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'reset');\" value='0'>0</button>
    606                         <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'up');\">+</button>
    607                       </div>";
    608                 } else {
    609                     //
    610                     // Let's see if a 'Key' directive was given. If so, we can add
    611                     // the transposed keys to the list.
    612                     //
    613                     if (strlen($this->arrDirectives['key']) && in_array($this->arrDirectives['key'], $this->arrKeys)) {
    614                         $i = 0;
    615                         foreach ($this->arrTransposeValues[$this->arrDirectives['key']] as $val) {
    616                             $tvalues[] = (string)$i . ' => ' . $val;
    617                             $i++;
    618                         }
    619                     } else {
    620                         $tvalues = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11');
    621                     }
    622                     $interactionForm .= __('Transpose', 'chordpress') . "
    623                     <select class=\"cpress-form-control cpress-form-control-sm cpress-w-50 cpress-py-0 cpress-px-2 float-right\" id=\"selTranspose-%cpressID%\" onchange=\"transposeChords('%cpressID%', 'selTranspose-');return false;\" title=\"" . __('Only works for international key names', 'chordpress') . ".\">
    624                         <option value=\"0\">" . $tvalues[0] . "</option>
    625                         <option value=\"1\">" . $tvalues[1] . "</option>
    626                         <option value=\"2\">" . $tvalues[2] . "</option>
    627                         <option value=\"3\">" . $tvalues[3] . "</option>
    628                         <option value=\"4\">" . $tvalues[4] . "</option>
    629                         <option value=\"5\">" . $tvalues[5] . "</option>
    630                         <option value=\"6\">" . $tvalues[6] . "</option>
    631                         <option value=\"7\">" . $tvalues[7] . "</option>
    632                         <option value=\"8\">" . $tvalues[8] . "</option>
    633                         <option value=\"9\">" . $tvalues[9] . "</option>
    634                         <option value=\"10\">" . $tvalues[10] . "</option>
    635                         <option value=\"11\">" . $tvalues[11] . "</option>
    636                     </select>";
    637                 }
    638                 $interactionForm .=  "</div>";
    639             }
    640             $interactionForm .= "<div class='cpress-col cpress-text-end cpress-pr-0'>";
    641             if (!$this->hidePrint) {
    642                 $interactionForm .=  "<button class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"window.print();\">" . __('Print', 'chordpress') . "</button>\n";
    643             }
    644             $interactionForm .=  "</div>";
    645             $returnText .= $interactionForm . "</div>\n";
     1220        break;
     1221      case 2:
     1222        if ($this->displayHBNotation) {
     1223          $retVal = 'H';
     1224        } else {
     1225          $retVal = 'B';
    6461226        }
    647 
    648         $returnText .= "<div id=\"%cpressID%\" class=\"cpress\">\n";
    649 
    650         /**
    651          * Print header if directives exist
    652          */
    653         $randId = $this->random_string(true);
    654         if (strlen($this->arrDirectives['title']) && !$this->hideTitle) {
    655             $cpressID = str_replace(' ', '-', strtolower(trim($this->arrDirectives['title']))) . '-' . $randId;
    656             $returnText = str_replace('%cpressID%', $cpressID, $returnText);
    657             $returnText .= '<' . $this->titleLevel . '>' . $this->arrDirectives['title'] . '</' . $this->titleLevel . ">\n";
    658         } else {
    659             $cpressID = 'ccpress-id-' . $randId;
    660             $returnText = str_replace('%cpressID%', $cpressID, $returnText);
    661         }
    662 
    663         if (strlen($this->arrDirectives['subtitle']) && !$this->hideSubtitle) {
    664             $returnText .= '<' . $this->subtitleLevel . '>' . $this->arrDirectives['subtitle'] . '</' . $this->subtitleLevel . ">\n";
    665         }
    666 
    667         if (
    668             strlen($this->arrDirectives['album']) ||
    669             strlen($this->arrDirectives['artist']) ||
    670             strlen($this->arrDirectives['capo']) ||
    671             strlen($this->arrDirectives['composer']) ||
    672             strlen($this->arrDirectives['key']) ||
    673             strlen($this->arrDirectives['tempo']) ||
    674             strlen($this->arrDirectives['time']) ||
    675             strlen($this->arrDirectives['year'])
    676         ) {
    677             $returnText .= "<div class=\"cpress_meta\">\n";
    678             if (strlen($this->arrDirectives['composer']) && !$this->hideComposer) $returnText .= esc_html(__('Composer', 'chordpress')) . ': ' . $this->arrDirectives['composer'] . "<br>\n";
    679             if (strlen($this->arrDirectives['artist']) && !$this->hideArtist) $returnText .= esc_html(__('Artist', 'chordpress')) . ': ' . $this->arrDirectives['artist'] . "<br>\n";
    680             if (strlen($this->arrDirectives['year']) && !$this->hideYear) $returnText .= esc_html(__('Year', 'chordpress')) . ': ' . $this->arrDirectives['year'] . "<br>\n";
    681             if (strlen($this->arrDirectives['album']) && !$this->hideAlbum) $returnText .= esc_html(__('Album', 'chordpress')) . ': ' . $this->arrDirectives['album'] . "<br>\n";
    682 
    683             if (strlen($this->arrDirectives['key'])) {
    684                 $returnText .= esc_html(__('Key (original)', 'chordpress')) . ': ' . $this->arrDirectives['key'] . "<br>\n";
    685                 $returnText .= esc_html(__('Key (transposed)', 'chordpress')) . ': <span class="chord-hidable-%cpressID% key-%cpressID%-0">' . $this->arrDirectives['key'] . '</span>';
    686                 for ($t = 1; $t <= 11; $t++) {
    687                     $returnText .= '<span class="chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none">' . $this->arrTransposeValues[$this->arrDirectives['key']][$t] . '</span>';
    688                 }
    689                 $returnText .= "<br>\n";
    690             }
    691 
    692             if (strlen($this->arrDirectives['time'])) $returnText .= esc_html(__('Time', 'chordpress')) . ': ' . $this->arrDirectives['time'] . "<br>\n";
    693             if (strlen($this->arrDirectives['tempo'])) $returnText .= esc_html(__('Tempo', 'chordpress')) . ': ' . $this->arrDirectives['tempo'] . "<br>\n";
    694             if (strlen($this->arrDirectives['capo'])) $returnText .= esc_html(__('Capo', 'chordpress')) . ': ' . $this->arrDirectives['capo'] . "<br>\n";
    695             $returnText = preg_replace('/<br>$/', '', $returnText); // Remove last <br>
    696             $returnText .= "</div>\n";
    697         }
    698 
    699         /**
    700          * Go through each line and process it
    701          */
    702         $this->inMonospace = false;
    703 //        $this->C->dnd($text, false);
    704         foreach ($text as $line) {
    705             if ($this->inMonospace && strpos($line, "{end_of_monospace}") === false) {
    706                 $returnText .= $line;
    707             } else {
    708 //                $this->C->dnd("IN: " . $line, false);
    709                 $returnText .= $this->formatAndDisplayLine($line);
    710 //                $this->C->dnd("OUT: " . $returnText, false);
    711             }
    712         }
    713         $returnText = str_replace('%cpressID%', $cpressID, $returnText);
    714 //        $this->C->dnd($returnText, false);
    715 
    716         /**
    717          * End of ChordPress song
    718          */
    719         $returnText .= "</div>\n<!--end: ChordPress SongSheet-->\n";
    720 
    721         /**
    722          * Build chord sheet if option set to true.
    723          */
    724         if ($this->showChordSheet) {
    725             $chordSheetText = "\n<!--begin: ChordPress ChordSheet-->\n";
    726             $chordSheetText .= "<div class='cpress_chordsheet'>\n";
    727             $chordSheetText .= "<div><hr></div>\n";
    728             $chordSheetText .= "<p><i>" . esc_html(__('These known chords are used in this song', 'chordpress')) . ".</i></p>";
    729             $this->uniqueChords = array_unique($this->allChords);
    730             foreach ($this->uniqueChords as $uc) {
    731                 if ($postid = $this->find_guitar_chord_post($uc)) {
    732                     $this->load_guitar_chord($postid);
    733                     $chordSheetText .= $this->C->createSvgChord(true);
    734                 }
    735             }
    736             $chordSheetText .= "</div>\n<div style=\"clear:both; padding: 16px 0 16px 0;\"><hr></div>\n<!--end: ChordPress ChordSheet-->\n\n";
    737             if ($this->showChordSheetOnTop) {
    738                 $returnText = $chordSheetText . $returnText;
    739             } else {
    740                 $returnText = $returnText . $chordSheetText;
    741             }
    742         }
    743 
    744         // $this->C->dnd($returnText);
    745         return $returnText . "\n\n";
    746     }
    747 
    748     //--------------------------------------------------------------------------
    749 
    750     /**
    751      * Process a single of the ChordPro text and return the formatted HTML.
    752      *
    753      * @param string $line - Single line from inside shortcode wrapper.
    754      * @return string - Formatted HTML.
    755      * @since 1.0.0
    756      */
    757     public function formatAndDisplayLine($line)
    758     {
    759         $returnText = "";
    760 
    761         /**
    762          * Array of chords
    763          */
    764         $arrChords = array();
    765 
    766         /**
    767          * Array of corresponding lyrics starting at a chord and ending prior
    768          * to the next chord or the end-of-line.
    769          */
    770         $arrLyrics = array();
    771 
    772         /**
    773          * Now check what this line is all about
    774          */
    775         if (substr_count($line, "[") == 0) {
    776             /**
    777              * No chords on this line
    778              */
    779             if (isset($line[0]) && ($line[0] == '#' || $line == '<br />')) {
    780                 /**
    781                  * Line starts with "#": It's a comment line => return empty string
    782                  */
    783                 return "";
    784             } else if ((isset($line[0]) && $line[0] == '{') || (isset($line[0]) && strpos($line, '{'))) {
    785                 /**
    786                  * Line starts with "{" or has one in it: It's a directive
    787                  * Some of them need consideration for the output
    788                  */
    789                 $directive = strstr($line, '{'); // Remove all before the {
    790                 $arrDirective = explode(":", $directive);
    791                 $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
    792                 if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
    793 
    794                 /**
    795                  * In case the directive had no colon and value, $directiveName will
    796                  * still contain the trailing }. So let's remove that.
    797                  */
    798                 if (substr_count($directiveName, "}")) $directiveName = str_replace("}", "", $directiveName);
    799 
    800                 if (strpos($directiveName, 'start_of_verse') !== false) {
    801                     return "<div class=\"cpress_verse\">\n<div class=\"cpress_line\">\n";
    802                 } elseif (strpos($directiveName, 'end_of_verse') !== false) {
    803                     return "</div></div>\n";
    804                 } elseif (strpos($directiveName, 'start_of_chorus') !== false) {
    805                     return "<div class=\"cpress_chorus\">\n<div class=\"cpress_line\">\n";
    806                 } elseif (strpos($directiveName, 'end_of_chorus') !== false) {
    807                     return "</div></div>\n";
    808                 } elseif (strpos($directiveName, 'start_of_monospace') !== false) {
    809                     $this->inMonospace = true;
    810                     return "<pre>\n";
    811                 } elseif (strpos($directiveName, 'end_of_monospace') !== false) {
    812                     $this->inMonospace = false;
    813                     return "</pre>\n";
    814                 } elseif (
    815                     strpos($directiveName, 'title') !== false ||
    816                     strpos($directiveName, 'subtitle') !== false ||
    817                     strpos($directiveName, 'album') !== false ||
    818                     strpos($directiveName, 'artist') !== false ||
    819                     strpos($directiveName, 'capo') !== false ||
    820                     strpos($directiveName, 'composer') !== false ||
    821                     strpos($directiveName, 'key') !== false ||
    822                     strpos($directiveName, 'tempo') !== false ||
    823                     strpos($directiveName, 'time') !== false ||
    824                     strpos($directiveName, 'year') !== false ||
    825                     strpos($directiveName, 'artist') !== false
    826                 ) {
    827                     //
    828                     // We have already processed these directives. Just return empty for this line.
    829                     //
    830                     return "";
    831                 } elseif (strpos($directiveName, 'comment') !== false && !$this->hideComments) {
    832                     $arrLyrics[] = '<span class="cpress_comment">' . $directiveValue . '</span>';
    833                 }
    834             } else {
    835                 /**
    836                  * Just lyrics without chords => print it
    837                  */
    838                 $arrLyrics[] = $line;
    839             }
    840         } elseif (substr_count($line, "[") != substr_count($line, "]")) {
    841             /**
    842              * Square bracket missing in this line
    843              */
    844             $arrLyrics[] = '<span style="color:#FF0000;"><i>' . esc_html(__('Missing square bracket in line', 'chordpress')) . ':</i></span> <code>' . $line . "</code>";
    845         } else {
    846             /**
    847              * Chords found. Split the line into segments beginning with '['
    848              */
    849             $arrBracketSegments = explode("[", $line);
    850             foreach ($arrBracketSegments as $segment) {
    851                 if (strlen($segment)) {
    852                     $pad = ($segment[strlen($segment) - 1] == ' ') ? '&nbsp;' : '';
    853                     /**
    854                      * Does the first segment start before the 1st '['?
    855                      */
    856                     if (substr_count($segment, "]") == 0) {
    857                         $arrChords[] = " ";
    858                         $arrLyrics[] = $segment . $pad;
    859                     } else {
    860                         /**
    861                          * Split this segment into chord an lyrics
    862                          */
    863                         $arrChordLyric = explode("]", $segment);
    864                         $arrChords[] = trim($arrChordLyric[0]);
    865                         $arrLyrics[] = $arrChordLyric[1] . $pad;
    866                     }
    867                 }
    868             }
    869         }
    870 
    871         /**
    872          * Start of line wrapper (lyrics and chords)
    873          */
    874         $returnText .= "<div class=\"cpress_line\">\n";
    875 
    876         /**
    877          * Align chords and lyrics together by wrapping each in a floating inline div
    878          */
    879         if (!$this->hideChords) {
    880 
    881             for ($i = 0; $i < count($arrChords); $i++) {
    882 
    883                 if (strlen(trim($arrChords[$i])) > 0 || strlen(trim($arrLyrics[$i])) > 0) {
    884 
    885                     $lyrics = trim($this->stripTags($arrLyrics[$i]));
    886 
    887                     /**
    888                      * Start of line-section (one chord and its lyrics)
    889                      */
    890                     $returnText .= "<div class=\"cpress_line_section\">\n";
    891 
    892                     if (strlen(trim($arrChords[$i])) > 0) {
    893 
    894                         $returnText .= "<div class=\"chord chord-hidable-%cpressID% key-%cpressID%-0\"><span class=\"chordshort\">";
    895 
    896                         /**
    897                          * Allow chords starting with a ~, |, / and . as chord placeholders. Just return the string.
    898                          * Att: ... will end up as &ellip; . Use blanks between each dot.
    899                          */
    900                         if (in_array($arrChords[$i][0], ['~', '|', '/', '.'])) {
    901                             $returnText .= $arrChords[$i];
    902                         } else {
    903                             $theChord = $this->formatChord($arrChords[$i]);
    904                             $this->allChords[] = $theChord;
    905                             $returnText .= $theChord;
    906                         }
    907 
    908                         $returnText .= "</span>&nbsp;</div>\n";
    909 
    910                         /**
    911                          * Prepare all other 11 transposed versions of the chord
    912                          * but hide them. They need to be on the page for interactive
    913                          * mode to show/hide them via Javascript.
    914                          * But do not mark empty chord divs as hidable. They need to stay.
    915                          */
    916                         $returnText .= "\n";
    917                         $tempTranspose = $this->getTranspose();
    918 
    919                         for ($t = 1; $t <= 11; $t++) {
    920                             $this->setTranspose($t);
    921                             /**
    922                              * Allow chords starting with a ~ as chord placeholders. Just return the string.
    923                              */
    924                             if (in_array($arrChords[$i][0], ['~', '|', '/', '.'])) {
    925                                 $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $arrChords[$i] . '</span>&nbsp;</div>';
    926                                 $returnText .= "\n";
    927                             } else {
    928                                 /**
    929                                  * This is a real chord.
    930                                  */
    931                                 $theChord = $this->formatChord($arrChords[$i]);
    932                                 $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $theChord . '</span>&nbsp;</div>';
    933                             }
    934                         }
    935 
    936                         $this->setTranspose($tempTranspose);
    937 
    938                         /**
    939                          * Now add the lyrics for this section.
    940                          */
    941                         $returnText .= '<div class="lyric">';
    942 
    943                         if (strlen($lyrics) > 0) {
    944                             $endOf1stWord = strpos($lyrics, ' ');
    945                             $numSpaces = substr_count($lyrics, ' ');
    946                             if ($endOf1stWord > 0 && $numSpaces == 1) {
    947                                 $returnText .= substr($lyrics, 0, $endOf1stWord) . '&nbsp;';
    948                                 $lyrics = substr($lyrics, $endOf1stWord);
    949                                 $returnText .= "</div></div>\n<div class=\"cpress_line_section\">\n<div class=\"chord\">&nbsp;</div><div class=\"lyric\">";
    950                             }
    951                         }
    952                     } else {
    953                         $returnText .= '<div class="chord">&nbsp;</div>';
    954                         $returnText .= '<div class="lyric">';
    955                     }
    956 
    957                     if (strlen($lyrics) > 0) $returnText .= $lyrics;
    958                     $returnText .= "</div>\n"; // end of lyric
    959                     $returnText .= "</div>\n"; // end of line
    960 
    961                 }
    962             }
    963 
    964             /**
    965              * If there are more lyric parts than chord parts, add them here
    966              */
    967             for ($i = count($arrChords); $i < count($arrLyrics); $i++) {
    968                 $returnText .= $arrLyrics[$i];
    969             }
    970         } else {
    971 
    972             /**
    973              * Hide chords was selected, so only show the lyrics
    974              */
    975             $returnText .= '<div class="cpress_line_section"><div class="lyric">';
    976 
    977             for ($i = 0; $i < count($arrLyrics); $i++) {
    978                 $returnText .= $arrLyrics[$i];
    979             }
    980 
    981             $returnText .= "</div></div>";
    982         }
    983 
    984         /**
    985          * End of line wrapper
    986          */
    987         $returnText .= "</div>\n";
    988 
    989         /**
    990          * Add a clear:both div
    991          */
    992         $returnText .= "<div class='cpress_clear'></div>\n";
    993 
    994         return $returnText;
    995     }
    996 
    997     //--------------------------------------------------------------------------
    998 
    999     /**
    1000      * Remove all <> wrapped text from a string.
    1001      *
    1002      * @param string $string - String to process.
    1003      * @return string - Stripped text.
    1004      * @since 1.0.0
    1005      */
    1006     private function stripTags($string)
    1007     {
    1008         $retString = "";
    1009         $isVisible = true;
    1010         for ($i = 0; $i < strlen($string); $i++) {
    1011             if ($isVisible) {
    1012                 if ($string[$i] == '<')
    1013                     $isVisible = false;
    1014                 else
    1015                     $retString .= $string[$i];
    1016             } elseif ($string[$i] == '>') {
    1017                 $isVisible = true;
    1018             }
    1019         }
    1020         return $retString;
    1021     }
    1022 
    1023     //--------------------------------------------------------------------------
    1024 
    1025     /**
    1026      * Processes a note text and returns the formatted HTML.
    1027      *
    1028      * @param string $ch - Chord text, e.g. "A" or "B#" or "Db/F" or "IV".
    1029      * @return string - Uppercase note string.
    1030      * @since 1.0.0
    1031      */
    1032     public function formatChord($ch)
    1033     {
    1034         $useFlats = false;
    1035         if (strlen($ch) == 0) return '';
    1036 
    1037         /**
    1038          * Return other valid chord identifiers as is
    1039          */
    1040         $italianChords = array('Do', 'do', 'Re', 're', 'Mi', 'mi', 'Fa', 'fa', 'Sol', 'sol', 'La', 'la', 'Si', 'si');
    1041         $nashvilleChords = array('1', '2', '3', '4', '5', '6', '7');
    1042         $romanChords = array('I', 'I7', 'II', 'III', 'iii', 'IV', 'V', 'V7', 'VI', 'vi', 'VI7', 'vi7', 'VII');
    1043         if (in_array($ch, $italianChords) or in_array($ch, $nashvilleChords) or in_array($ch, $romanChords)) return $ch;
    1044 
    1045         /**
    1046          * The first letter should be the key note
    1047          */
    1048         $note = substr($ch, 0, 1);
    1049         $rem = substr($ch, 1);
    1050 
    1051         /**
    1052          * Convert note to a number
    1053          */
    1054         $noteVal = $this->noteToNumber($note);
    1055 
    1056         /**
    1057          * Check sharp/flat
    1058          */
    1059         if (strlen($rem) > 0) {
    1060             if (substr($rem, 0, 1) == '#') {
    1061                 $noteVal++;
    1062                 $rem = substr($rem, 1);
    1063             } elseif (strncasecmp($rem, "b", 1) == 0) {
    1064                 $useFlats = true;
    1065                 $noteVal--;
    1066                 $rem = substr($rem, 1);
    1067             }
    1068         }
    1069 
    1070         /**
    1071          * Add transpose
    1072          */
    1073         $noteVal += $this->transpose;
    1074         if ($noteVal > 11) $noteVal -= 12;
    1075         if ($noteVal < 0) $noteVal += 12;
    1076 
    1077         /**
    1078          * Build note to display from numeric note value
    1079          */
    1080         $xlatedNote = $this->numberToNote($noteVal, $useFlats);
    1081         // die($this->pretty_dump($xlatedNote));
    1082 
    1083         /**
    1084          * Return the chord display plus the bass note (if any)
    1085          */
    1086         return $xlatedNote . $this->formatRemainder($rem);
    1087     }
    1088 
    1089     //--------------------------------------------------------------------------
    1090 
    1091     /**
    1092      * Process the remainder of the given chord.
    1093      *
    1094      * @param string $remainder - Chord text starting at second char.
    1095      * @return string - Formatted remainder.
    1096      * @since 1.0.0
    1097      */
    1098     public function formatRemainder($remainder)
    1099     {
    1100         $indexOfSlash = strpos($remainder, '/');
    1101         if ($indexOfSlash === false) return $remainder;
    1102 
    1103         /**
    1104          * We have a slash, indicating that a bass note follows.
    1105          * Break the string into 2 parts at the slash.
    1106          * The slash will be lost, and will need to be added back later.
    1107          */
    1108         $chord = substr($remainder, 0, $indexOfSlash);
    1109         $bass = substr($remainder, $indexOfSlash + 1);
    1110 
    1111         $useFlats = false;
    1112 
    1113         if (strlen($bass) == 0) return $chord . "/?";
    1114 
    1115         /**
    1116          * The first letter should be the bass note
    1117          */
    1118         $note = substr($bass, 0, 1);
    1119         $xlatedNote = $note;
    1120         $rem = substr($bass, 1);
    1121 
    1122         /**
    1123          * Convert note to a number
    1124          */
    1125         $noteVal = $this->noteToNumber($note);
    1126 
    1127         /**
    1128          * Check sharp/flat
    1129          */
    1130         if (strlen($rem) > 0) {
    1131             if (substr($rem, 0, 1) == '#') {
    1132                 $noteVal++;
    1133                 $rem = substr($rem, 1);
    1134             } elseif (strncasecmp($rem, "b", 1) == 0) {
    1135                 $useFlats = true;
    1136                 $noteVal--;
    1137                 $rem = substr($rem, 1);
    1138             }
    1139         }
    1140 
    1141         /**
    1142          * Add transpose
    1143          */
    1144         $noteVal += $this->transpose;
    1145         if ($noteVal > 11) $noteVal -= 12;
    1146         if ($noteVal < 0) $noteVal += 12;
    1147 
    1148         /**
    1149          * Build note to display from numeric note value
    1150          */
    1151         $xlatedNote = $this->numberToNote($noteVal);
    1152 
    1153         return $chord . "/" . $xlatedNote . $rem;
    1154     }
    1155 
    1156     //--------------------------------------------------------------------------
    1157 
    1158     /**
    1159      * Convert note to number.
    1160      *
    1161      * @param string $n - Note to convert.
    1162      * @return integer
    1163      * @since 1.0.0
    1164      */
    1165     public function noteToNumber($n)
    1166     {
    1167         $regularNotation = array(
    1168             'A' => 0,
    1169             'B' => 2,
    1170             'C' => 3,
    1171             'D' => 5,
    1172             'E' => 7,
    1173             'F' => 8,
    1174             'G' => 10,
    1175         );
    1176 
    1177         $hbNotation = array(
    1178             'A' => 0,
    1179             'B' => 1,
    1180             'H' => 2,
    1181             'C' => 3,
    1182             'D' => 5,
    1183             'E' => 7,
    1184             'F' => 8,
    1185             'G' => 10,
    1186         );
    1187 
    1188         if (in_array(strtolower($this->hbNotation), array("yes", "1", "true"))) {
    1189             if (array_key_exists(strtoupper($n), $hbNotation)) {
    1190                 return $hbNotation[strtoupper($n)];
    1191             } else {
    1192                 return 0;
    1193             }
    1194         } else {
    1195             if (array_key_exists(strtoupper($n), $regularNotation)) {
    1196                 return $regularNotation[strtoupper($n)];
    1197             } else {
    1198                 return 0;
    1199             }
    1200         }
    1201     }
    1202 
    1203     //--------------------------------------------------------------------------
    1204 
    1205     /**
    1206      * Convert number to note.
    1207      *
    1208      * @param integer $n - Numeric note value to convert to note string.
    1209      * @param boolean $useFlats - Whether to use flat notes or not.
    1210      * @return string
    1211      * @since 1.0.0
    1212      */
    1213     public function numberToNote($n, $useFlats = false)
    1214     {
    1215         $retVal = '';
    1216 
    1217         switch ($n) {
    1218             case 0:
    1219                 $retVal = 'A';
    1220                 break;
    1221             case 1:
    1222                 if ($this->displayHBNotation) {
    1223                     $retVal = 'B';
    1224                 } else {
    1225                     if ($useFlats) $retVal = "Bb";
    1226                     else $retVal = "A#";
    1227                 }
    1228                 break;
    1229             case 2:
    1230                 if ($this->displayHBNotation) {
    1231                     $retVal = 'H';
    1232                 } else {
    1233                     $retVal = 'B';
    1234                 }
    1235                 break;
    1236             case 3:
    1237                 $retVal = 'C';
    1238                 break;
    1239             case 4:
    1240                 if ($useFlats) $retVal = "Db";
    1241                 else $retVal = "C#";
    1242                 break;
    1243             case 5:
    1244                 $retVal = 'D';
    1245                 break;
    1246             case 6:
    1247                 if ($useFlats) $retVal = "Eb";
    1248                 else $retVal = "D#";
    1249                 break;
    1250             case 7:
    1251                 $retVal = 'E';
    1252                 break;
    1253             case 8:
    1254                 $retVal = 'F';
    1255                 break;
    1256             case 9:
    1257                 if ($useFlats) $retVal = "Gb";
    1258                 else $retVal = "F#";
    1259                 break;
    1260             case 10:
    1261                 $retVal = 'G';
    1262                 break;
    1263             case 11:
    1264                 if ($useFlats) $retVal = "Ab";
    1265                 else $retVal = "G#";
    1266                 break;
    1267         }
    1268         return $retVal;
    1269     }
    1270 
    1271     //--------------------------------------------------------------------------
    1272 
    1273     /**
    1274      * Set class variable: displayHBNotation.
    1275      *
    1276      * @param boolean $g
    1277      * @since 1.0.0
    1278      */
    1279     public function setDisplayHBNotation($g)
    1280     {
    1281         $this->displayHBNotation = $g;
    1282     }
    1283 
    1284     //--------------------------------------------------------------------------
    1285 
    1286     /**
    1287      * Get class variable: displayHBNotation.
    1288      *
    1289      * @return boolean
    1290      * @since 1.0.0
    1291      */
    1292     public function getDisplayHBNotation()
    1293     {
    1294         return $this->displayHBNotation;
    1295     }
    1296 
    1297     //--------------------------------------------------------------------------
    1298 
    1299     /**
    1300      * Set class variable: float.
    1301      *
    1302      * @param string $f - left/right/none/inherit.
    1303      * @since 1.0.0
    1304      */
    1305     public function setFloat($f)
    1306     {
    1307         $this->float = $f;
    1308     }
    1309 
    1310     //--------------------------------------------------------------------------
    1311 
    1312     /**
    1313      * Get class variable: float.
    1314      *
    1315      * @return string
    1316      * @since 1.0.0
    1317      */
    1318     public function getFloat()
    1319     {
    1320         return $this->float;
    1321     }
    1322 
    1323     //--------------------------------------------------------------------------
    1324 
    1325     /**
    1326      * Set class variable: hbNotation.
    1327      *
    1328      * @param string $g - yes/no.
    1329      * @since 1.0.0
    1330      */
    1331     public function setHBNotation($g)
    1332     {
    1333         $this->hbNotation = $g;
    1334     }
    1335 
    1336     //--------------------------------------------------------------------------
    1337 
    1338     /**
    1339      * Get class variable: hideChords.
    1340      *
    1341      * @return string -yes/no.
    1342      * @since 3.5.0
    1343      */
    1344     public function getHideChords()
    1345     {
    1346         return $this->hideChords;
    1347     }
    1348 
    1349     //--------------------------------------------------------------------------
    1350 
    1351     /**
    1352      * Set class variable: hideChords.
    1353      *
    1354      * @param string $g - yes/no.
    1355      * @since 3.5.0
    1356      */
    1357     public function setHideChords($g)
    1358     {
    1359         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1360             $this->hideChords = true;
    1361         } else {
    1362             $this->hideChords = false;
    1363         }
    1364     }
    1365 
    1366     //--------------------------------------------------------------------------
    1367 
    1368     /**
    1369      * Get class variable: hideComments.
    1370      *
    1371      * @return string -yes/no.
    1372      * @since 3.5.0
    1373      */
    1374     public function getHideComments()
    1375     {
    1376         return $this->hideComments;
    1377     }
    1378 
    1379     //--------------------------------------------------------------------------
    1380 
    1381     /**
    1382      * Set class variable: hideComments.
    1383      *
    1384      * @param string $g - yes/no.
    1385      * @since 3.5.0
    1386      */
    1387     public function setHideComments($g)
    1388     {
    1389         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1390             $this->hideComments = 1;
    1391         } else {
    1392             $this->hideComments = 0;
    1393         }
    1394     }
    1395 
    1396     //--------------------------------------------------------------------------
    1397 
    1398     /**
    1399      * Get class variable: hideComposer.
    1400      *
    1401      * @return string -yes/no.
    1402      * @since 3.5.0
    1403      */
    1404     public function getHideComposer()
    1405     {
    1406         return $this->hideComposer;
    1407     }
    1408 
    1409     //--------------------------------------------------------------------------
    1410 
    1411     /**
    1412      * Set class variable: hideComposer.
    1413      *
    1414      * @param string $g - yes/no.
    1415      * @since 3.5.0
    1416      */
    1417     public function setHideComposer($g)
    1418     {
    1419         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1420             $this->hideComposer = 1;
    1421         } else {
    1422             $this->hideComposer = 0;
    1423         }
    1424     }
    1425 
    1426     //--------------------------------------------------------------------------
    1427 
    1428     /**
    1429      * Get class variable: hidePrint.
    1430      *
    1431      * @return string -yes/no.
    1432      * @since 3.5.0
    1433      */
    1434     public function getHidePrint()
    1435     {
    1436         return $this->hidePrint;
    1437     }
    1438 
    1439     //--------------------------------------------------------------------------
    1440 
    1441     /**
    1442      * Set class variable: hidePrint.
    1443      *
    1444      * @param string $g - yes/no.
    1445      * @since 3.5.0
    1446      */
    1447     public function setHidePrint($g)
    1448     {
    1449         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1450             $this->hidePrint = 1;
    1451         } else {
    1452             $this->hidePrint = 0;
    1453         }
    1454     }
    1455 
    1456     //--------------------------------------------------------------------------
    1457 
    1458     /**
    1459      * Get class variable: hideSubtitle.
    1460      *
    1461      * @return string -yes/no.
    1462      * @since 3.5.0
    1463      */
    1464     public function getHideSubtitle()
    1465     {
    1466         return $this->hideSubtitle;
    1467     }
    1468 
    1469     //--------------------------------------------------------------------------
    1470 
    1471     /**
    1472      * Set class variable: hideSubtitle.
    1473      *
    1474      * @param string $g - yes/no.
    1475      * @since 3.5.0
    1476      */
    1477     public function setHideSubtitle($g)
    1478     {
    1479         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1480             $this->hideSubtitle = 1;
    1481         } else {
    1482             $this->hideSubtitle = 0;
    1483         }
    1484     }
    1485 
    1486     //--------------------------------------------------------------------------
    1487 
    1488     /**
    1489      * Get class variable: hideTitle.
    1490      *
    1491      * @return string -yes/no.
    1492      * @since 3.5.0
    1493      */
    1494     public function getHideTitle()
    1495     {
    1496         return $this->hideTitle;
    1497     }
    1498 
    1499     //--------------------------------------------------------------------------
    1500 
    1501     /**
    1502      * Set class variable: hideTitle.
    1503      *
    1504      * @param string $g - yes/no.
    1505      * @since 3.5.0
    1506      */
    1507     public function setHideTitle($g)
    1508     {
    1509         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1510             $this->hideTitle = 1;
    1511         } else {
    1512             $this->hideTitle = 0;
    1513         }
    1514     }
    1515 
    1516     //--------------------------------------------------------------------------
    1517 
    1518     /**
    1519      * Get class variable: hideTranspose.
    1520      *
    1521      * @return string -yes/no.
    1522      * @since 3.5.0
    1523      */
    1524     public function getHideTranspose()
    1525     {
    1526         return $this->hideTranspose;
    1527     }
    1528 
    1529     //--------------------------------------------------------------------------
    1530 
    1531     /**
    1532      * Set class variable: hideTranspose.
    1533      *
    1534      * @param string $g - yes/no.
    1535      * @since 3.5.0
    1536      */
    1537     public function setHideTranspose($g)
    1538     {
    1539         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1540             $this->hideTranspose = 1;
    1541         } else {
    1542             $this->hideTranspose = 0;
    1543         }
    1544     }
    1545 
    1546     //--------------------------------------------------------------------------
    1547 
    1548     /**
    1549      * Get class variable: showNumericTranspose.
    1550      *
    1551      * @return string -yes/no.
    1552      * @since 3.6.0
    1553      */
    1554     public function getNumericTranspose()
    1555     {
    1556         return $this->showNumericTranspose;
    1557     }
    1558 
    1559     //--------------------------------------------------------------------------
    1560 
    1561     /**
    1562      * Set class variable: showNumericTranspose.
    1563      *
    1564      * @param string $g - yes/no.
    1565      * @since 3.6.0
    1566      */
    1567     public function setNumericTranspose($g)
    1568     {
    1569         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1570             $this->showNumericTranspose = 1;
    1571         } else {
    1572             $this->showNumericTranspose = 0;
    1573         }
    1574     }
    1575 
    1576     //--------------------------------------------------------------------------
    1577 
    1578     /**
    1579      * Get class variable: fixedInteraction.
    1580      *
    1581      * @return string -yes/no.
    1582      * @since 3.6.0
    1583      */
    1584     public function getFixedInteraction()
    1585     {
    1586         return $this->fixedInteraction;
    1587     }
    1588 
    1589     //--------------------------------------------------------------------------
    1590 
    1591     /**
    1592      * Set class variable: fixedInteraction.
    1593      *
    1594      * @param string $g - yes/no.
    1595      * @since 3.6.0
    1596      */
    1597     public function setFixedInteraction($g)
    1598     {
    1599         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1600             $this->fixedInteraction = 1;
    1601         } else {
    1602             $this->fixedInteraction = 0;
    1603         }
    1604     }
    1605 
    1606     //--------------------------------------------------------------------------
    1607 
    1608     /**
    1609      * Get class variable: hideYear.
    1610      *
    1611      * @return string -yes/no.
    1612      * @since 3.5.0
    1613      */
    1614     public function getHideYear()
    1615     {
    1616         return $this->hideYear;
    1617     }
    1618 
    1619     //--------------------------------------------------------------------------
    1620 
    1621     /**
    1622      * Set class variable: hideYear.
    1623      *
    1624      * @param string $g - yes/no.
    1625      * @since 3.5.0
    1626      */
    1627     public function setHideYear($g)
    1628     {
    1629         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1630             $this->hideYear = 1;
    1631         } else {
    1632             $this->hideYear = 0;
    1633         }
    1634     }
    1635 
    1636     //--------------------------------------------------------------------------
    1637 
    1638     /**
    1639      * Get class variable: hbNotation.
    1640      *
    1641      * @return string -yes/no.
    1642      * @since 1.0.0
    1643      */
    1644     public function getHBNotation()
    1645     {
    1646         return $this->hbNotation;
    1647     }
    1648 
    1649     //--------------------------------------------------------------------------
    1650 
    1651     /**
    1652      * Set class variable: interactive.
    1653      *
    1654      * @param string $g - yes/no.
    1655      * @since 1.0.0
    1656      */
    1657     public function setInteractive($i)
    1658     {
    1659         $this->interactive = $i;
    1660     }
    1661 
    1662     //--------------------------------------------------------------------------
    1663 
    1664     /**
    1665      * Get class variable: interactive.
    1666      *
    1667      * @return string - yes/no.
    1668      * @since 1.0.0
    1669      */
    1670     public function getInteractive()
    1671     {
    1672         return $this->interactive;
    1673     }
    1674 
    1675     //--------------------------------------------------------------------------
    1676 
    1677     /**
    1678      * Get class variable: showChordSheet.
    1679      *
    1680      * @return string -yes/no.
    1681      * @since 3.5.0
    1682      */
    1683     public function getShowChordSheet()
    1684     {
    1685         return $this->showChordSheet;
    1686     }
    1687 
    1688     //--------------------------------------------------------------------------
    1689 
    1690     /**
    1691      * Set class variable: hideYear.
    1692      *
    1693      * @param string $g - yes/no.
    1694      * @since 3.5.0
    1695      */
    1696     public function setShowChordSheet($g)
    1697     {
    1698         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1699             $this->showChordSheet = 1;
    1700         } else {
    1701             $this->showChordSheet = 0;
    1702         }
    1703     }
    1704 
    1705     //--------------------------------------------------------------------------
    1706 
    1707     /**
    1708      * Get class variable: showChordSheetOnTop.
    1709      *
    1710      * @return string -yes/no.
    1711      * @since 3.5.0
    1712      */
    1713     public function getShowChordSheetOnTop()
    1714     {
    1715         return $this->showChordSheetOnTop;
    1716     }
    1717 
    1718     //--------------------------------------------------------------------------
    1719 
    1720     /**
    1721      * Set class variable: hideYear.
    1722      *
    1723      * @param string $g - yes/no.
    1724      * @since 3.5.0
    1725      */
    1726     public function setShowChordSheetOnTop($g)
    1727     {
    1728         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1729             $this->showChordSheetOnTop = 1;
    1730         } else {
    1731             $this->showChordSheetOnTop = 0;
    1732         }
    1733     }
    1734 
    1735     //--------------------------------------------------------------------------
    1736 
    1737     /**
    1738      * Sets class variable: transpose.
    1739      *
    1740      * @param integer $t - Positive or negative number of steps for transponation.
    1741      * @since 1.0.0
    1742      */
    1743     public function setTranspose($t)
    1744     {
    1745         $this->transpose = $t;
    1746     }
    1747 
    1748     //--------------------------------------------------------------------------
    1749 
    1750     /**
    1751      * Get class variable: transpose.
    1752      *
    1753      * @return integer
    1754      * @since 1.0.0
    1755      */
    1756     public function getTranspose()
    1757     {
    1758         return $this->transpose;
    1759     }
    1760 
    1761     //--------------------------------------------------------------------------
    1762 
    1763     /**
    1764      * Find a guitar chord type post by shortname.
    1765      *
    1766      * @param string $shortname - Shortname of the guitar post to look for.
    1767      * @return integer - Post ID or NULL
    1768      */
    1769     private function find_guitar_chord_post($shortname)
    1770     {
    1771         $query_args = array(
    1772             'posts_per_page' => 1,
    1773             'post_type' => 'guitar_chord',
    1774             'meta_key' => 'guitar_chord_name',
    1775             'meta_value' => $shortname
    1776         );
    1777         $query_result = new WP_Query($query_args);
    1778 
    1779         if (array_key_exists(0, $query_result->posts)) {
    1780             return $query_result->posts[0]->ID;
    1781         } else {
    1782             return 0;
    1783         }
    1784     }
    1785 
    1786     //--------------------------------------------------------------------------
    1787 
    1788     /**
    1789      * Load a guitar chord based on post ID.
    1790      *
    1791      * @param integer $postid - Guitar chord post ID.
    1792      * @return void
    1793      */
    1794     private function load_guitar_chord($postid)
    1795     {
    1796         $my_chord = array();
    1797         $post = get_post($postid);
    1798 
    1799         /**
    1800          * Retrieve meta data from chord post
    1801          */
    1802         $guitar_chord_name = get_post_meta($postid, 'guitar_chord_name', true);
    1803         if (get_post_meta($postid, 'guitar_chord_barres', true)) {
    1804             $guitar_chord_barres = get_post_meta($postid, 'guitar_chord_barres', true);
    1805         } else {
    1806             $guitar_chord_barres = "";
    1807         }
    1808         $guitar_chord_fingers = get_post_meta($postid, 'guitar_chord_fingers', true);
    1809         $guitar_chord_frets = get_post_meta($postid, 'guitar_chord_frets', true);
    1810         $guitar_chord_strings = get_post_meta($postid, 'guitar_chord_strings', true);
    1811         $guitar_chord_position = get_post_meta($postid, 'guitar_chord_position', true);
    1812         $guitar_chord_tuning = get_post_meta($postid, 'guitar_chord_tuning', true);
    1813 
    1814         /**
    1815          * Set chord properties
    1816          */
    1817         $this->C->setProperty('title', $guitar_chord_name);
    1818         $this->C->setBarres($guitar_chord_barres);
    1819         $this->C->setProperty('fingers', $this->C->replace_brackets($guitar_chord_fingers));
    1820         $this->C->setProperty('frets', $guitar_chord_frets);
    1821         $this->C->setProperty('position', $guitar_chord_position);
    1822         $this->C->setProperty('strings', $guitar_chord_strings);
    1823         $this->C->setTuning($guitar_chord_tuning);
    1824     }
    1825 
    1826     //--------------------------------------------------------------------------
    1827     /**
    1828      * Create a modal guitar chord dialog.
    1829      *
    1830      * @param integer $postid - ID of the chord post
    1831      * @param string $chord - Vexchord HTML
    1832      * @return string - Modal chord dialog HTML
    1833      */
     1227        break;
     1228      case 3:
     1229        $retVal = 'C';
     1230        break;
     1231      case 4:
     1232        if ($useFlats) $retVal = "Db";
     1233        else $retVal = "C#";
     1234        break;
     1235      case 5:
     1236        $retVal = 'D';
     1237        break;
     1238      case 6:
     1239        if ($useFlats) $retVal = "Eb";
     1240        else $retVal = "D#";
     1241        break;
     1242      case 7:
     1243        $retVal = 'E';
     1244        break;
     1245      case 8:
     1246        $retVal = 'F';
     1247        break;
     1248      case 9:
     1249        if ($useFlats) $retVal = "Gb";
     1250        else $retVal = "F#";
     1251        break;
     1252      case 10:
     1253        $retVal = 'G';
     1254        break;
     1255      case 11:
     1256        if ($useFlats) $retVal = "Ab";
     1257        else $retVal = "G#";
     1258        break;
     1259    }
     1260    return $retVal;
     1261  }
     1262
     1263  //---------------------------------------------------------------------------
     1264  /**
     1265   * Set class variable: displayHBNotation.
     1266   *
     1267   * @param boolean $g
     1268   * @since 1.0.0
     1269   */
     1270  public function setDisplayHBNotation($g) {
     1271    $this->displayHBNotation = $g;
     1272  }
     1273
     1274  //---------------------------------------------------------------------------
     1275  /**
     1276   * Get class variable: displayHBNotation.
     1277   *
     1278   * @return boolean
     1279   * @since 1.0.0
     1280   */
     1281  public function getDisplayHBNotation() {
     1282    return $this->displayHBNotation;
     1283  }
     1284
     1285  //---------------------------------------------------------------------------
     1286  /**
     1287   * Set class variable: float.
     1288   *
     1289   * @param string $f - left/right/none/inherit.
     1290   * @since 1.0.0
     1291   */
     1292  public function setFloat($f) {
     1293    $this->float = $f;
     1294  }
     1295
     1296  //---------------------------------------------------------------------------
     1297  /**
     1298   * Get class variable: float.
     1299   *
     1300   * @return string
     1301   * @since 1.0.0
     1302   */
     1303  public function getFloat() {
     1304    return $this->float;
     1305  }
     1306
     1307  //---------------------------------------------------------------------------
     1308  /**
     1309   * Set class variable: hbNotation.
     1310   *
     1311   * @param string $g - yes/no.
     1312   * @since 1.0.0
     1313   */
     1314  public function setHBNotation($g) {
     1315    $this->hbNotation = $g;
     1316  }
     1317
     1318  //---------------------------------------------------------------------------
     1319  /**
     1320   * Get class variable: hideChords.
     1321   *
     1322   * @return string -yes/no.
     1323   * @since 3.5.0
     1324   */
     1325  public function getHideChords() {
     1326    return $this->hideChords;
     1327  }
     1328
     1329  //---------------------------------------------------------------------------
     1330  /**
     1331   * Set class variable: hideChords.
     1332   *
     1333   * @param string $g - yes/no.
     1334   * @since 3.5.0
     1335   */
     1336  public function setHideChords($g) {
     1337    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1338      $this->hideChords = true;
     1339    } else {
     1340      $this->hideChords = false;
     1341    }
     1342  }
     1343
     1344  //---------------------------------------------------------------------------
     1345  /**
     1346   * Get class variable: hideComments.
     1347   *
     1348   * @return string -yes/no.
     1349   * @since 3.5.0
     1350   */
     1351  public function getHideComments() {
     1352    return $this->hideComments;
     1353  }
     1354
     1355  //---------------------------------------------------------------------------
     1356  /**
     1357   * Set class variable: hideComments.
     1358   *
     1359   * @param string $g - yes/no.
     1360   * @since 3.5.0
     1361   */
     1362  public function setHideComments($g) {
     1363    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1364      $this->hideComments = 1;
     1365    } else {
     1366      $this->hideComments = 0;
     1367    }
     1368  }
     1369
     1370  //---------------------------------------------------------------------------
     1371  /**
     1372   * Get class variable: hideComposer.
     1373   *
     1374   * @return string -yes/no.
     1375   * @since 3.5.0
     1376   */
     1377  public function getHideComposer() {
     1378    return $this->hideComposer;
     1379  }
     1380
     1381  //---------------------------------------------------------------------------
     1382  /**
     1383   * Set class variable: hideComposer.
     1384   *
     1385   * @param string $g - yes/no.
     1386   * @since 3.5.0
     1387   */
     1388  public function setHideComposer($g) {
     1389    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1390      $this->hideComposer = 1;
     1391    } else {
     1392      $this->hideComposer = 0;
     1393    }
     1394  }
     1395
     1396  //---------------------------------------------------------------------------
     1397  /**
     1398   * Get class variable: hidePrint.
     1399   *
     1400   * @return string -yes/no.
     1401   * @since 3.5.0
     1402   */
     1403  public function getHidePrint() {
     1404    return $this->hidePrint;
     1405  }
     1406
     1407  //---------------------------------------------------------------------------
     1408  /**
     1409   * Set class variable: hidePrint.
     1410   *
     1411   * @param string $g - yes/no.
     1412   * @since 3.5.0
     1413   */
     1414  public function setHidePrint($g) {
     1415    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1416      $this->hidePrint = 1;
     1417    } else {
     1418      $this->hidePrint = 0;
     1419    }
     1420  }
     1421
     1422  //---------------------------------------------------------------------------
     1423  /**
     1424   * Get class variable: hideSubtitle.
     1425   *
     1426   * @return string -yes/no.
     1427   * @since 3.5.0
     1428   */
     1429  public function getHideSubtitle() {
     1430    return $this->hideSubtitle;
     1431  }
     1432
     1433  //---------------------------------------------------------------------------
     1434  /**
     1435   * Set class variable: hideSubtitle.
     1436   *
     1437   * @param string $g - yes/no.
     1438   * @since 3.5.0
     1439   */
     1440  public function setHideSubtitle($g) {
     1441    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1442      $this->hideSubtitle = 1;
     1443    } else {
     1444      $this->hideSubtitle = 0;
     1445    }
     1446  }
     1447
     1448  //---------------------------------------------------------------------------
     1449  /**
     1450   * Get class variable: hideTitle.
     1451   *
     1452   * @return string -yes/no.
     1453   * @since 3.5.0
     1454   */
     1455  public function getHideTitle() {
     1456    return $this->hideTitle;
     1457  }
     1458
     1459  //---------------------------------------------------------------------------
     1460  /**
     1461   * Set class variable: hideTitle.
     1462   *
     1463   * @param string $g - yes/no.
     1464   * @since 3.5.0
     1465   */
     1466  public function setHideTitle($g) {
     1467    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1468      $this->hideTitle = 1;
     1469    } else {
     1470      $this->hideTitle = 0;
     1471    }
     1472  }
     1473
     1474  //---------------------------------------------------------------------------
     1475  /**
     1476   * Get class variable: hideTranspose.
     1477   *
     1478   * @return string -yes/no.
     1479   * @since 3.5.0
     1480   */
     1481  public function getHideTranspose() {
     1482    return $this->hideTranspose;
     1483  }
     1484
     1485  //---------------------------------------------------------------------------
     1486  /**
     1487   * Set class variable: hideTranspose.
     1488   *
     1489   * @param string $g - yes/no.
     1490   * @since 3.5.0
     1491   */
     1492  public function setHideTranspose($g) {
     1493    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1494      $this->hideTranspose = 1;
     1495    } else {
     1496      $this->hideTranspose = 0;
     1497    }
     1498  }
     1499
     1500  //---------------------------------------------------------------------------
     1501  /**
     1502   * Get class variable: showNumericTranspose.
     1503   *
     1504   * @return string -yes/no.
     1505   * @since 3.6.0
     1506   */
     1507  public function getNumericTranspose() {
     1508    return $this->showNumericTranspose;
     1509  }
     1510
     1511  //---------------------------------------------------------------------------
     1512  /**
     1513   * Set class variable: showNumericTranspose.
     1514   *
     1515   * @param string $g - yes/no.
     1516   * @since 3.6.0
     1517   */
     1518  public function setNumericTranspose($g) {
     1519    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1520      $this->showNumericTranspose = 1;
     1521    } else {
     1522      $this->showNumericTranspose = 0;
     1523    }
     1524  }
     1525
     1526  //---------------------------------------------------------------------------
     1527  /**
     1528   * Get class variable: fixedInteraction.
     1529   *
     1530   * @return string -yes/no.
     1531   * @since 3.6.0
     1532   */
     1533  public function getFixedInteraction() {
     1534    return $this->fixedInteraction;
     1535  }
     1536
     1537  //---------------------------------------------------------------------------
     1538  /**
     1539   * Set class variable: fixedInteraction.
     1540   *
     1541   * @param string $g - yes/no.
     1542   * @since 3.6.0
     1543   */
     1544  public function setFixedInteraction($g) {
     1545    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1546      $this->fixedInteraction = 1;
     1547    } else {
     1548      $this->fixedInteraction = 0;
     1549    }
     1550  }
     1551
     1552  //---------------------------------------------------------------------------
     1553  /**
     1554   * Get class variable: hideYear.
     1555   *
     1556   * @return string -yes/no.
     1557   * @since 3.5.0
     1558   */
     1559  public function getHideYear() {
     1560    return $this->hideYear;
     1561  }
     1562
     1563  //---------------------------------------------------------------------------
     1564  /**
     1565   * Set class variable: hideYear.
     1566   *
     1567   * @param string $g - yes/no.
     1568   * @since 3.5.0
     1569   */
     1570  public function setHideYear($g) {
     1571    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1572      $this->hideYear = 1;
     1573    } else {
     1574      $this->hideYear = 0;
     1575    }
     1576  }
     1577
     1578  //---------------------------------------------------------------------------
     1579  /**
     1580   * Get class variable: hbNotation.
     1581   *
     1582   * @return string -yes/no.
     1583   * @since 1.0.0
     1584   */
     1585  public function getHBNotation() {
     1586    return $this->hbNotation;
     1587  }
     1588
     1589  //---------------------------------------------------------------------------
     1590  /**
     1591   * Set class variable: interactive.
     1592   *
     1593   * @param string $g - yes/no.
     1594   * @since 1.0.0
     1595   */
     1596  public function setInteractive($i) {
     1597    $this->interactive = $i;
     1598  }
     1599
     1600  //---------------------------------------------------------------------------
     1601  /**
     1602   * Get class variable: interactive.
     1603   *
     1604   * @return string - yes/no.
     1605   * @since 1.0.0
     1606   */
     1607  public function getInteractive() {
     1608    return $this->interactive;
     1609  }
     1610
     1611  //---------------------------------------------------------------------------
     1612  /**
     1613   * Get class variable: showChordSheet.
     1614   *
     1615   * @return string -yes/no.
     1616   * @since 3.5.0
     1617   */
     1618  public function getShowChordSheet() {
     1619    return $this->showChordSheet;
     1620  }
     1621
     1622  //---------------------------------------------------------------------------
     1623  /**
     1624   * Set class variable: hideYear.
     1625   *
     1626   * @param string $g - yes/no.
     1627   * @since 3.5.0
     1628   */
     1629  public function setShowChordSheet($g) {
     1630    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1631      $this->showChordSheet = 1;
     1632    } else {
     1633      $this->showChordSheet = 0;
     1634    }
     1635  }
     1636
     1637  //---------------------------------------------------------------------------
     1638  /**
     1639   * Get class variable: showChordSheetOnTop.
     1640   *
     1641   * @return string -yes/no.
     1642   * @since 3.5.0
     1643   */
     1644  public function getShowChordSheetOnTop() {
     1645    return $this->showChordSheetOnTop;
     1646  }
     1647
     1648  //---------------------------------------------------------------------------
     1649  /**
     1650   * Set class variable: hideYear.
     1651   *
     1652   * @param string $g - yes/no.
     1653   * @since 3.5.0
     1654   */
     1655  public function setShowChordSheetOnTop($g) {
     1656    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1657      $this->showChordSheetOnTop = 1;
     1658    } else {
     1659      $this->showChordSheetOnTop = 0;
     1660    }
     1661  }
     1662
     1663  //---------------------------------------------------------------------------
     1664  /**
     1665   * Sets class variable: transpose.
     1666   *
     1667   * @param integer $t - Positive or negative number of steps for transponation.
     1668   * @since 1.0.0
     1669   */
     1670  public function setTranspose($t) {
     1671    $this->transpose = $t;
     1672  }
     1673
     1674  //---------------------------------------------------------------------------
     1675  /**
     1676   * Get class variable: transpose.
     1677   *
     1678   * @return integer
     1679   * @since 1.0.0
     1680   */
     1681  public function getTranspose() {
     1682    return $this->transpose;
     1683  }
     1684
     1685  //---------------------------------------------------------------------------
     1686  /**
     1687   * Find a guitar chord type post by shortname.
     1688   *
     1689   * @param string $shortname - Shortname of the guitar post to look for.
     1690   * @return integer - Post ID or NULL
     1691   */
     1692  private function find_guitar_chord_post($shortname) {
     1693    $query_args = array(
     1694      'posts_per_page' => 1,
     1695      'post_type' => 'guitar_chord',
     1696      'meta_key' => 'guitar_chord_name',
     1697      'meta_value' => $shortname
     1698    );
     1699    $query_result = new WP_Query($query_args);
     1700
     1701    if (array_key_exists(0, $query_result->posts)) {
     1702      return $query_result->posts[0]->ID;
     1703    } else {
     1704      return 0;
     1705    }
     1706  }
     1707
     1708  //---------------------------------------------------------------------------
     1709  /**
     1710   * Load a guitar chord based on post ID.
     1711   *
     1712   * @param integer $postid - Guitar chord post ID.
     1713   * @return void
     1714   */
     1715  private function load_guitar_chord($postid) {
     1716    $my_chord = array();
     1717    $post = get_post($postid);
     1718
     1719    /**
     1720     * Retrieve meta data from chord post
     1721     */
     1722    $guitar_chord_name = get_post_meta($postid, 'guitar_chord_name', true);
     1723    if (get_post_meta($postid, 'guitar_chord_barres', true)) {
     1724      $guitar_chord_barres = get_post_meta($postid, 'guitar_chord_barres', true);
     1725    } else {
     1726      $guitar_chord_barres = "";
     1727    }
     1728    $guitar_chord_fingers = get_post_meta($postid, 'guitar_chord_fingers', true);
     1729    $guitar_chord_frets = get_post_meta($postid, 'guitar_chord_frets', true);
     1730    $guitar_chord_strings = get_post_meta($postid, 'guitar_chord_strings', true);
     1731    $guitar_chord_position = get_post_meta($postid, 'guitar_chord_position', true);
     1732    $guitar_chord_tuning = get_post_meta($postid, 'guitar_chord_tuning', true);
     1733
     1734    /**
     1735     * Set chord properties
     1736     */
     1737    $this->C->setProperty('title', $guitar_chord_name);
     1738    $this->C->setBarres($guitar_chord_barres);
     1739    $this->C->setProperty('fingers', $this->C->replace_brackets($guitar_chord_fingers));
     1740    $this->C->setProperty('frets', $guitar_chord_frets);
     1741    $this->C->setProperty('position', $guitar_chord_position);
     1742    $this->C->setProperty('strings', $guitar_chord_strings);
     1743    $this->C->setTuning($guitar_chord_tuning);
     1744  }
     1745
     1746  //---------------------------------------------------------------------------
     1747  /**
     1748   * Create a modal guitar chord dialog.
     1749   *
     1750   * @param integer $postid - ID of the chord post
     1751   * @param string $chord - Vexchord HTML
     1752   * @return string - Modal chord dialog HTML
     1753   */
    18341754//    private function create_modal_chord($postid, $chord)
    18351755//    {
     
    18641784//    }
    18651785
    1866     //--------------------------------------------------------------------------
    1867     /**
    1868      * Generate random string.
    1869      *
    1870      * @param boolean $alphaonly - Whether to only use alpha charaters
    1871      * @param integer $length - Length of random string to generate
    1872      * @return false|string
    1873      */
    1874     private function random_string($alphaonly = false, $length = 15)
    1875     {
    1876         if ($alphaonly) {
    1877             return substr(str_shuffle(str_repeat($x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
    1878         } else {
    1879             return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
    1880         }
    1881     }
    1882 
    1883     // ---------------------------------------------------------------------------
    1884 
    1885     /**
    1886      * Dump and Die.
    1887      *
    1888      * @param array $a Array to print out pretty
    1889      * @param bool $die Flag to die after dump or not
    1890      * @return string
    1891      * @since 3.2.0
    1892      */
    1893     private function dnd($a, $die = true)
    1894     {
    1895         $dump = highlight_string("<?php\n\$data =\n" . var_export($a, true) . ";\n?>");
    1896         if ($die) die($dump);
    1897         else return $dump;
    1898     }
     1786  //---------------------------------------------------------------------------
     1787  /**
     1788   * Generate random string.
     1789   *
     1790   * @param boolean $alphaonly - Whether to only use alpha charaters
     1791   * @param integer $length - Length of random string to generate
     1792   * @return false|string
     1793   */
     1794  private function random_string($alphaonly = false, $length = 15) {
     1795    if ($alphaonly) {
     1796      return substr(str_shuffle(str_repeat($x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
     1797    } else {
     1798      return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
     1799    }
     1800  }
     1801
     1802  //---------------------------------------------------------------------------
     1803  /**
     1804   * Dump and Die.
     1805   *
     1806   * @param array $a Array to print out pretty
     1807   * @param bool $die Flag to die after dump or not
     1808   * @return string
     1809   * @since 3.2.0
     1810   */
     1811  private function dnd($a, $die = true) {
     1812    $dump = highlight_string("<?php\n\$data =\n" . var_export($a, true) . ";\n?>");
     1813    if ($die) die($dump);
     1814    else return $dump;
     1815  }
    18991816}
  • chordpress/tags/3.6.1/languages/chordpress.pot

    r2996248 r3067783  
    1 # Copyright (C) 2023 George Lewe
     1# Copyright (C) 2024 George Lewe
    22# This file is distributed under the same license as the Lewe ChordPress plugin.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Lewe ChordPress 3.6.0\n"
     5"Project-Id-Version: Lewe ChordPress 3.6.1\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/chordpress\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2023-11-15T10:11:19+01:00\n"
     12"POT-Creation-Date: 2024-04-09T17:41:13+02:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.4.0\n"
     
    12201220msgstr ""
    12211221
    1222 #: includes/class-chordpress-renderer.php:592
     1222#: includes/class-chordpress-renderer.php:595
    12231223msgid "Font"
    12241224msgstr ""
    12251225
    1226 #: includes/class-chordpress-renderer.php:602
    1227 #: includes/class-chordpress-renderer.php:622
     1226#: includes/class-chordpress-renderer.php:605
     1227#: includes/class-chordpress-renderer.php:625
    12281228msgid "Transpose"
    12291229msgstr ""
    12301230
    1231 #: includes/class-chordpress-renderer.php:623
     1231#: includes/class-chordpress-renderer.php:626
    12321232msgid "Only works for international key names"
    12331233msgstr ""
    12341234
    1235 #: includes/class-chordpress-renderer.php:642
     1235#: includes/class-chordpress-renderer.php:645
    12361236msgid "Print"
    12371237msgstr ""
    12381238
    1239 #: includes/class-chordpress-renderer.php:678
     1239#: includes/class-chordpress-renderer.php:681
    12401240msgid "Composer"
    12411241msgstr ""
    12421242
    1243 #: includes/class-chordpress-renderer.php:679
     1243#: includes/class-chordpress-renderer.php:682
    12441244msgid "Artist"
    12451245msgstr ""
    12461246
    1247 #: includes/class-chordpress-renderer.php:680
     1247#: includes/class-chordpress-renderer.php:683
    12481248msgid "Year"
    12491249msgstr ""
    12501250
    1251 #: includes/class-chordpress-renderer.php:681
     1251#: includes/class-chordpress-renderer.php:684
    12521252msgid "Album"
    12531253msgstr ""
    12541254
    1255 #: includes/class-chordpress-renderer.php:684
     1255#: includes/class-chordpress-renderer.php:687
    12561256msgid "Key (original)"
    12571257msgstr ""
    12581258
    1259 #: includes/class-chordpress-renderer.php:685
     1259#: includes/class-chordpress-renderer.php:688
    12601260msgid "Key (transposed)"
    12611261msgstr ""
    12621262
    1263 #: includes/class-chordpress-renderer.php:692
     1263#: includes/class-chordpress-renderer.php:695
    12641264msgid "Time"
    12651265msgstr ""
    12661266
    1267 #: includes/class-chordpress-renderer.php:693
     1267#: includes/class-chordpress-renderer.php:696
    12681268msgid "Tempo"
    12691269msgstr ""
    12701270
    1271 #: includes/class-chordpress-renderer.php:694
     1271#: includes/class-chordpress-renderer.php:697
    12721272msgid "Capo"
    12731273msgstr ""
    12741274
    1275 #: includes/class-chordpress-renderer.php:728
     1275#: includes/class-chordpress-renderer.php:731
    12761276msgid "These known chords are used in this song"
    12771277msgstr ""
    12781278
    1279 #: includes/class-chordpress-renderer.php:844
     1279#: includes/class-chordpress-renderer.php:845
    12801280msgid "Missing square bracket in line"
    12811281msgstr ""
  • chordpress/tags/3.6.1/makepot.cmd

    r2877462 r3067783  
    1 D:\xampp8.1.12\php\php.exe D:/wp-cli.phar i18n make-pot . languages/chordpress.pot --slug=chordpress --include="*.php,admin/*.php,admin/partials/*.php,includes/*.php,public/*.php,public/partials/*.php"
     1D:\xampp8.2.12\php\php.exe D:/wp-cli.phar i18n make-pot . languages/chordpress.pot --slug=chordpress --include="*.php,admin/*.php,admin/partials/*.php,includes/*.php,public/*.php,public/partials/*.php"
  • chordpress/tags/3.6.1/readme.txt

    r2996248 r3067783  
    44Tags: chordpro,chord,chords,lyrics,music,notes,sheet,sound,guitar
    55Requires at least: 4.0
    6 Tested up to: 6.4
    7 Stable tag: 3.6.0
     6Tested up to: 6.5
     7Stable tag: 3.6.1
    88Requires PHP: 5.2.4
    99License: GPLv3
     
    130130
    131131== Changelog ==
     132= 3.6.1 =
     133* 2024-04-09
     134* WordPress 6.5 compatibility
     135* Added '-' as allowed chord prefix
     136
    132137= 3.6.0 =
    133138* 2023-11-15
  • chordpress/tags/3.6.1/uninstall.php

    r2996248 r3067783  
    1414 */
    1515if (!defined('WP_UNINSTALL_PLUGIN')) {
    16     exit;
     16  exit;
    1717}
    1818
     
    3232 */
    3333if (get_option($pname . '_checkbox_uninstall_delete_options')) {
    34     $options = array(
    35         $pname . '_checkbox_fixed_interaction',
    36         $pname . '_checkbox_hide_album',
    37         $pname . '_checkbox_hide_artist',
    38         $pname . '_checkbox_hide_chords',
    39         $pname . '_checkbox_hide_comments',
    40         $pname . '_checkbox_hide_composer',
    41         $pname . '_checkbox_hide_print',
    42         $pname . '_checkbox_hide_subtitle',
    43         $pname . '_checkbox_hide_title',
    44         $pname . '_checkbox_hide_transpose',
    45         $pname . '_checkbox_hide_year',
    46         $pname . '_checkbox_hb_notation',
    47         $pname . '_checkbox_show_chord_sheet',
    48         $pname . '_checkbox_show_jtab_sheet',
    49         $pname . '_checkbox_show_chord_sheet_on_top',
    50         $pname . '_checkbox_show_numeric_transpose',
    51         $pname . '_select_title_level',
    52         $pname . '_select_subtitle_level',
    53         $pname . '_text_meta_style',
    54         $pname . '_text_chord_style',
    55         $pname . '_text_lyrics_style',
    56         $pname . '_text_comment_style',
    57         $pname . '_text_chorus_style',
    58         $pname . '_text_verse_style',
    59         $pname . '_text_line_style',
    60         $pname . '_text_chord_backgroundColor',
    61         $pname . '_number_chord_barreChordRadius',
    62         $pname . '_text_chord_barreChordStrokeColor',
    63         $pname . '_number_chord_barreChordStrokeWidth',
    64         $pname . '_number_chord_canvasWidth',
    65         $pname . '_text_chord_color',
    66         $pname . '_number_chord_emptyStringIndicatorSize',
    67         $pname . '_checkbox_chord_fixedDiagramPosition',
    68         $pname . '_text_chord_fontFamily',
    69         $pname . '_text_chord_fretColor',
    70         $pname . '_text_chord_fretLabelColor',
    71         $pname . '_text_chord_fretLabelColor',
    72         $pname . '_select_chord_fretLabelPosition',
    73         $pname . '_number_chord_fretLabelFontSize',
    74         $pname . '_number_chord_frets',
    75         $pname . '_number_chord_fretSize',
    76         $pname . '_number_chord_nutSize',
    77         $pname . '_text_chord_nutColor',
    78         $pname . '_text_chord_nutStrokeColor',
    79         $pname . '_number_chord_nutStrokeWidth',
    80         $pname . '_text_chord_nutTextColor',
    81         $pname . '_number_chord_nutTextSize',
    82         $pname . '_number_chord_position',
    83         $pname . '_number_chord_sidePadding',
    84         $pname . '_text_chord_stringColor',
    85         $pname . '_select_chord_strings',
    86         $pname . '_number_chord_strokeWidth',
    87         $pname . '_select_chord_style',
    88         $pname . '_number_chord_titleBottomMargin',
    89         $pname . '_text_chord_titleColor',
    90         $pname . '_number_chord_titleFontSize',
    91         $pname . '_number_chord_topFretWidth',
    92         $pname . '_text_chord_tuning',
    93         $pname . '_text_chord_tuningsColor',
    94         $pname . '_number_chord_tuningsFontSize',
    95     );
     34  $options = array(
     35    $pname . '_checkbox_fixed_interaction',
     36    $pname . '_checkbox_hide_album',
     37    $pname . '_checkbox_hide_artist',
     38    $pname . '_checkbox_hide_chords',
     39    $pname . '_checkbox_hide_comments',
     40    $pname . '_checkbox_hide_composer',
     41    $pname . '_checkbox_hide_print',
     42    $pname . '_checkbox_hide_subtitle',
     43    $pname . '_checkbox_hide_title',
     44    $pname . '_checkbox_hide_transpose',
     45    $pname . '_checkbox_hide_year',
     46    $pname . '_checkbox_hb_notation',
     47    $pname . '_checkbox_show_chord_sheet',
     48    $pname . '_checkbox_show_jtab_sheet',
     49    $pname . '_checkbox_show_chord_sheet_on_top',
     50    $pname . '_checkbox_show_numeric_transpose',
     51    $pname . '_select_title_level',
     52    $pname . '_select_subtitle_level',
     53    $pname . '_text_meta_style',
     54    $pname . '_text_chord_style',
     55    $pname . '_text_lyrics_style',
     56    $pname . '_text_comment_style',
     57    $pname . '_text_chorus_style',
     58    $pname . '_text_verse_style',
     59    $pname . '_text_line_style',
     60    $pname . '_text_chord_backgroundColor',
     61    $pname . '_number_chord_barreChordRadius',
     62    $pname . '_text_chord_barreChordStrokeColor',
     63    $pname . '_number_chord_barreChordStrokeWidth',
     64    $pname . '_number_chord_canvasWidth',
     65    $pname . '_text_chord_color',
     66    $pname . '_number_chord_emptyStringIndicatorSize',
     67    $pname . '_checkbox_chord_fixedDiagramPosition',
     68    $pname . '_text_chord_fontFamily',
     69    $pname . '_text_chord_fretColor',
     70    $pname . '_text_chord_fretLabelColor',
     71    $pname . '_text_chord_fretLabelColor',
     72    $pname . '_select_chord_fretLabelPosition',
     73    $pname . '_number_chord_fretLabelFontSize',
     74    $pname . '_number_chord_frets',
     75    $pname . '_number_chord_fretSize',
     76    $pname . '_number_chord_nutSize',
     77    $pname . '_text_chord_nutColor',
     78    $pname . '_text_chord_nutStrokeColor',
     79    $pname . '_number_chord_nutStrokeWidth',
     80    $pname . '_text_chord_nutTextColor',
     81    $pname . '_number_chord_nutTextSize',
     82    $pname . '_number_chord_position',
     83    $pname . '_number_chord_sidePadding',
     84    $pname . '_text_chord_stringColor',
     85    $pname . '_select_chord_strings',
     86    $pname . '_number_chord_strokeWidth',
     87    $pname . '_select_chord_style',
     88    $pname . '_number_chord_titleBottomMargin',
     89    $pname . '_text_chord_titleColor',
     90    $pname . '_number_chord_titleFontSize',
     91    $pname . '_number_chord_topFretWidth',
     92    $pname . '_text_chord_tuning',
     93    $pname . '_text_chord_tuningsColor',
     94    $pname . '_number_chord_tuningsFontSize',
     95  );
    9696
    97     foreach ($options as $option) {
    98         delete_option($option);
    99     }
     97  foreach ($options as $option) {
     98    delete_option($option);
     99  }
    100100}
    101101
     
    105105 */
    106106if (get_option($pname . '_checkbox_uninstall_delete_chordposts')) {
    107     $args = array(
    108         'post_type' => 'guitar_chord',
    109         'posts_per_page' => -1
    110     );
    111     $query = new WP_Query ($args);
    112     while ($query->have_posts()) {
    113         $query->the_post();
    114         $id = get_the_ID();
    115         wp_delete_post($id, true);
    116     }
    117     wp_reset_postdata();
     107  $args = array(
     108    'post_type' => 'guitar_chord',
     109    'posts_per_page' => -1
     110  );
     111  $query = new WP_Query ($args);
     112  while ($query->have_posts()) {
     113    $query->the_post();
     114    $id = get_the_ID();
     115    wp_delete_post($id, true);
     116  }
     117  wp_reset_postdata();
    118118
    119     global $wp_post_types;
    120     if (isset($wp_post_types['guitar_chord'])) {
    121         unset($wp_post_types['guitar_chord']);
    122     }
     119  global $wp_post_types;
     120  if (isset($wp_post_types['guitar_chord'])) {
     121    unset($wp_post_types['guitar_chord']);
     122  }
    123123}
  • chordpress/trunk/admin/partials/chordpress-admin-options.php

    r2996248 r3067783  
    980980                            <td>
    981981                                <ul class="description" style="list-style: square; margin-left:12px;">
    982                                     <li>The <a href="https://www.chordpro.org" title="ChordPro" rel="nofollow ugc">ChordPro</a> team</li>
    983                                     <li><a href="https://profiles.wordpress.org/rlisle/" title="@rlisle" rel="nofollow ugc">@rlisle</a> for his work on the ChordsAndLyrics plugin that he created in 2009</li>
    984                                     <li>Ahkâm for the beautiful <a href="https://www.freeiconspng.com/img/17579" title="ChordPress Plugin Icon" rel="nofollow ugc">ChordPress Plugin Icon</a></li>
    985                                     <li>The fine people maintaining the <a href="https://github.com/omnibrain/svguitar" title="SVGuitar" rel="nofollow ugc">SVGuitar</a> module</li>
     982                                    <li>The <a href="https://www.chordpro.org" title="ChordPro" rel="nofollow ugc" target="_blank">ChordPro</a> team</li>
     983                                    <li><a href="https://profiles.wordpress.org/rlisle/" title="@rlisle" rel="nofollow ugc" target="_blank">@rlisle</a> for his work on the ChordsAndLyrics plugin that he created in 2009</li>
     984                                    <li>Ahkâm for the beautiful <a href="https://www.freeiconspng.com/img/17579" title="ChordPress Plugin Icon" rel="nofollow ugc" target="_blank">ChordPress Plugin Icon</a></li>
     985                                    <li>The fine people maintaining the <a href="https://github.com/omnibrain/svguitar" title="SVGuitar" rel="nofollow ugc" target="_blank">SVGuitar</a> module</li>
    986986                                </ul>
    987987                            </td>
  • chordpress/trunk/chordpress.php

    r2996248 r3067783  
    1717 * Plugin URI:        https://lewe.gitbook.io/lewe-chordpress/
    1818 * Description:       This plugin renders ChordPro formatted text and chord diagrams in WordPress sites.
    19  * Version:           3.6.0
     19 * Version:           3.6.1
    2020 * Author:            George Lewe
    2121 * Author URI:        https://www.lewe.com
     
    3636 */
    3737define('CHORDPRESS_NAME', 'ChordPress');
    38 define('CHORDPRESS_VERSION', '3.6.0');
     38define('CHORDPRESS_VERSION', '3.6.1');
    3939define('CHORDPRESS_AUTHOR', 'George Lewe');
    4040define('CHORDPRESS_AUTHOR_URI', 'https://www.lewe.com');
     
    5252 * This action is documented in includes/class-chordpress-activator.php
    5353 */
    54 function activate_chordpress()
    55 {
    56     require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-activator.php';
    57     ChordPress_Activator::activate();
     54function activate_chordpress() {
     55  require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-activator.php';
     56  ChordPress_Activator::activate();
    5857}
     58
    5959register_activation_hook(__FILE__, 'activate_chordpress');
    6060
     
    6363 * This action is documented in includes/class-chordpress-deactivator.php
    6464 */
    65 function deactivate_chordpress()
    66 {
    67     require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-deactivator.php';
    68     ChordPress_Deactivator::deactivate();
     65function deactivate_chordpress() {
     66  require_once plugin_dir_path(__FILE__) . 'includes/class-chordpress-deactivator.php';
     67  ChordPress_Deactivator::deactivate();
    6968}
     69
    7070register_deactivation_hook(__FILE__, 'deactivate_chordpress');
    7171
     
    100100 * @since    1.0.0
    101101 */
    102 function run_chordpress()
    103 {
    104     $plugin = new ChordPress_Plugin();
    105     $plugin->run();
     102function run_chordpress() {
     103  $plugin = new ChordPress_Plugin();
     104  $plugin->run();
    106105}
     106
    107107run_chordpress();
  • chordpress/trunk/includes/class-chordpress-renderer.php

    r2996248 r3067783  
    2020 * @author     George Lewe <george@lewe.com>
    2121 */
    22 class ChordPress_Renderer
    23 {
    24     /**
    25      * Guitar chord instance.
    26      *
    27      * @since    2.1.0
    28      * @access   private
    29      * @var      ChordPress_Chord $C Guitar chord instance.
    30      */
    31     private $C;
    32 
    33     /**
    34      * Display H/B notation flag.
    35      *
    36      * @since    1.0.0
    37      * @access   private
    38      * @var      boolean $displayHBNotation Display H/B notation flag.
    39      */
    40     private $displayHBNotation;
    41 
    42     /**
    43      * Hide album flag.
    44      *
    45      * @since    1.0.0
    46      * @access   private
    47      * @var      boolean $hideAlbum Hide album flag.
    48      */
    49     private $hideAlbum;
    50 
    51     /**
    52      * Hide artist flag.
    53      *
    54      * @since    1.0.0
    55      * @access   private
    56      * @var      boolean $hideArtist Hide artist flag.
    57      */
    58     private $hideArtist;
    59 
    60     /**
    61      * Hide chords flag.
    62      *
    63      * @since    1.0.0
    64      * @access   private
    65      * @var      boolean $hideChords Hide chords flag.
    66      */
    67     private $hideChords;
    68 
    69     /**
    70      * Hide comments flag.
    71      *
    72      * @since    1.0.0
    73      * @access   private
    74      * @var      boolean $hideComments Hide comments flag.
    75      */
    76     private $hideComments;
    77 
    78     /**
    79      * Hide composer flag.
    80      *
    81      * @since    1.0.0
    82      * @access   private
    83      * @var      boolean $hideComposer Hide composer flag.
    84      */
    85     private $hideComposer;
    86 
    87     /**
    88      * Hide subtitle flag.
    89      *
    90      * @since    1.0.0
    91      * @access   private
    92      * @var      boolean $hideSubtitle Hide subtitle flag.
    93      */
    94     private $hideSubtitle;
    95 
    96     /**
    97      * Hide print button.
    98      *
    99      * @since    1.0.0
    100      * @access   private
    101      * @var      boolean $hidePrint Hide print button.
    102      */
    103     private $hidePrint;
    104 
    105     /**
    106      * Hide title flag.
    107      *
    108      * @since    1.0.0
    109      * @access   private
    110      * @var      boolean $hideTitle Hide title flag.
    111      */
    112     private $hideTitle;
    113 
    114     /**
    115      * Hide transpose button.
    116      *
    117      * @since    1.0.0
    118      * @access   private
    119      * @var      boolean $hideTranspose Hide transpose button
    120      */
    121     private $hideTranspose;
    122 
    123     /**
    124      * Show numeric transpose input.
    125      *
    126      * @since    3.6.0
    127      * @access   private
    128      * @var      boolean $showNumericTranspose Hide transpose button
    129      */
    130     private $showNumericTranspose;
    131 
    132     /**
    133      * Place interaction bar fixed at bottom of page.
    134      *
    135      * @since    3.6.0
    136      * @access   private
    137      * @var      boolean $fixedInteraction
    138      */
    139     private $fixedInteraction;
    140 
    141     /**
    142      * Hide year flag.
    143      *
    144      * @since    1.0.0
    145      * @access   private
    146      * @var      boolean $hideYear Hide year flag.
    147      */
    148     private $hideYear;
    149 
    150     /**
    151      * HTML header level for title.
    152      *
    153      * @since    1.0.0
    154      * @access   private
    155      * @var      string $titleLevel HTML header level for title.
    156      */
    157     private $titleLevel;
    158 
    159     /**
    160      * HTML header level for subtitle.
    161      *
    162      * @since    1.0.0
    163      * @access   private
    164      * @var      string $subtitleLevel HTML header level for subtitle.
    165      */
    166     private $subtitleLevel;
    167 
    168     /**
    169      * CSS styles for meta info.
    170      *
    171      * @since    1.0.0
    172      * @access   private
    173      * @var      string $metaStyle CSS styles for meta info.
    174      */
    175     private $metaStyle;
    176 
    177     /**
    178      * CSS text color for chords.
    179      *
    180      * @since    1.0.0
    181      * @access   private
    182      * @var      string $chordTextcolor CSS text color for chords.
    183      */
    184     private $chordTextcolor;
    185 
    186     /**
    187      * CSS text size for chords.
    188      *
    189      * @since    1.0.0
    190      * @access   private
    191      * @var      string $chordTextsize CSS text size for chords.
    192      */
    193     private $chordTextsize;
    194 
    195     /**
    196      * CSS text color for lyrics.
    197      *
    198      * @since    1.0.0
    199      * @access   private
    200      * @var      string $lyricsTextcolor CSS text color for lyrics.
    201      */
    202     private $lyricsTextcolor;
    203 
    204     /**
    205      * CSS text size for lyrics.
    206      *
    207      * @since    1.0.0
    208      * @access   private
    209      * @var      string $lyricsTextsize CSS text size for lyrics.
    210      */
    211     private $lyricsTextsize;
    212 
    213     /**
    214      * CSS styles for lyrics.
    215      *
    216      * @since    2.3.0
    217      * @access   private
    218      * @var      string $lyricsStyle CSS styles for lyrics.
    219      */
    220     private $lyricsStyle;
    221 
    222     /**
    223      * CSS styles for comments.
    224      *
    225      * @since    1.0.0
    226      * @access   private
    227      * @var      string $commentStyle CSS styles for comments.
    228      */
    229     private $commentStyle;
    230 
    231     /**
    232      * CSS styles for the chords.
    233      *
    234      * @since    1.0.0
    235      * @access   private
    236      * @var      string $chordStyle CSS styles for the chorus sections.
    237      */
    238     private $chordStyle;
    239 
    240     /**
    241      * CSS styles for the chorus sections.
    242      *
    243      * @since    1.0.0
    244      * @access   private
    245      * @var      string $chorusStyle CSS styles for the chorus sections.
    246      */
    247     private $chorusStyle;
    248 
    249     /**
    250      * CSS styles for the verse sections.
    251      *
    252      * @since    1.0.0
    253      * @access   private
    254      * @var      string $verseStyle CSS styles for the verse sections.
    255      */
    256     private $verseStyle;
    257 
    258     /**
    259      * CSS styles for the line sections.
    260      *
    261      * @since    3.1.2
    262      * @access   private
    263      * @var      string $lineStyle CSS styles for the line sections.
    264      */
    265     private $lineStyle;
    266 
    267     /**
    268      * CSS float directive: no/left/right.
    269      *
    270      * @since    1.5.0
    271      * @access   private
    272      * @var      string $float CSS float directive: no/left/right.
    273      */
    274     private $float;
    275 
    276     /**
    277      * Shortcode directive hbNotation: no/yes.
    278      *
    279      * @since    1.0.0
    280      * @access   private
    281      * @var      string $hbNotation Shortcode directive hbNotation: no/yes.
    282      */
    283     private $hbNotation;
    284 
    285     /**
    286      * Show Chord Sheet for Vexchords.
    287      *
    288      * @since    2.1.0
    289      * @access   private
    290      * @var      string $showChordSheet Show Chord Sheet: no/yes.
    291      */
    292     private $showChordSheet;
    293 
    294     /**
    295      * Show Chord Sheet on top.
    296      *
    297      * @since    2.1.0
    298      * @access   private
    299      * @var      string $showChordSheetOnTop Show Chord Sheet on top: no/yes.
    300      */
    301     private $showChordSheetOnTop;
    302 
    303     /**
    304      * Shortcode directive interactive: no/yes.
    305      *
    306      * @since    1.5.0
    307      * @access   private
    308      * @var      string $interactive Shortcode directive interactive: no/yes.
    309      */
    310     private $interactive;
    311 
    312     /**
    313      * Shortcode directive transpose: 0-11 (semitones).
    314      *
    315      * @since    1.0.0
    316      * @access   private
    317      * @var      string $transpose Shortcode directive transpose: 0-11 (semitones).
    318      */
    319     private $transpose;
    320 
    321     /**
    322      * Array of supported ChordPro directives.
    323      *
    324      * @since    1.0.0
    325      * @access   private
    326      * @var      array $arrDirectives Array of supported ChordPro directives.
    327      */
    328     private $arrDirectives = array(
    329         'album' => '',
    330         'artist' => '',
    331         'capo' => '',
    332         'composer' => '',
    333         'key' => '',
    334         'subtitle' => '',
    335         'tempo' => '',
    336         'time' => '',
    337         'title' => '',
    338         'year' => '',
     22class ChordPress_Renderer {
     23  /**
     24   * Guitar chord instance.
     25   *
     26   * @since    2.1.0
     27   * @access   private
     28   * @var      ChordPress_Chord $C Guitar chord instance.
     29   */
     30  private $C;
     31
     32  /**
     33   * Display H/B notation flag.
     34   *
     35   * @since    1.0.0
     36   * @access   private
     37   * @var      boolean $displayHBNotation Display H/B notation flag.
     38   */
     39  private $displayHBNotation;
     40
     41  /**
     42   * Hide album flag.
     43   *
     44   * @since    1.0.0
     45   * @access   private
     46   * @var      boolean $hideAlbum Hide album flag.
     47   */
     48  private $hideAlbum;
     49
     50  /**
     51   * Hide artist flag.
     52   *
     53   * @since    1.0.0
     54   * @access   private
     55   * @var      boolean $hideArtist Hide artist flag.
     56   */
     57  private $hideArtist;
     58
     59  /**
     60   * Hide chords flag.
     61   *
     62   * @since    1.0.0
     63   * @access   private
     64   * @var      boolean $hideChords Hide chords flag.
     65   */
     66  private $hideChords;
     67
     68  /**
     69   * Hide comments flag.
     70   *
     71   * @since    1.0.0
     72   * @access   private
     73   * @var      boolean $hideComments Hide comments flag.
     74   */
     75  private $hideComments;
     76
     77  /**
     78   * Hide composer flag.
     79   *
     80   * @since    1.0.0
     81   * @access   private
     82   * @var      boolean $hideComposer Hide composer flag.
     83   */
     84  private $hideComposer;
     85
     86  /**
     87   * Hide subtitle flag.
     88   *
     89   * @since    1.0.0
     90   * @access   private
     91   * @var      boolean $hideSubtitle Hide subtitle flag.
     92   */
     93  private $hideSubtitle;
     94
     95  /**
     96   * Hide print button.
     97   *
     98   * @since    1.0.0
     99   * @access   private
     100   * @var      boolean $hidePrint Hide print button.
     101   */
     102  private $hidePrint;
     103
     104  /**
     105   * Hide title flag.
     106   *
     107   * @since    1.0.0
     108   * @access   private
     109   * @var      boolean $hideTitle Hide title flag.
     110   */
     111  private $hideTitle;
     112
     113  /**
     114   * Hide transpose button.
     115   *
     116   * @since    1.0.0
     117   * @access   private
     118   * @var      boolean $hideTranspose Hide transpose button
     119   */
     120  private $hideTranspose;
     121
     122  /**
     123   * Show numeric transpose input.
     124   *
     125   * @since    3.6.0
     126   * @access   private
     127   * @var      boolean $showNumericTranspose Hide transpose button
     128   */
     129  private $showNumericTranspose;
     130
     131  /**
     132   * Place interaction bar fixed at bottom of page.
     133   *
     134   * @since    3.6.0
     135   * @access   private
     136   * @var      boolean $fixedInteraction
     137   */
     138  private $fixedInteraction;
     139
     140  /**
     141   * Hide year flag.
     142   *
     143   * @since    1.0.0
     144   * @access   private
     145   * @var      boolean $hideYear Hide year flag.
     146   */
     147  private $hideYear;
     148
     149  /**
     150   * HTML header level for title.
     151   *
     152   * @since    1.0.0
     153   * @access   private
     154   * @var      string $titleLevel HTML header level for title.
     155   */
     156  private $titleLevel;
     157
     158  /**
     159   * HTML header level for subtitle.
     160   *
     161   * @since    1.0.0
     162   * @access   private
     163   * @var      string $subtitleLevel HTML header level for subtitle.
     164   */
     165  private $subtitleLevel;
     166
     167  /**
     168   * CSS styles for meta info.
     169   *
     170   * @since    1.0.0
     171   * @access   private
     172   * @var      string $metaStyle CSS styles for meta info.
     173   */
     174  private $metaStyle;
     175
     176  /**
     177   * CSS text color for chords.
     178   *
     179   * @since    1.0.0
     180   * @access   private
     181   * @var      string $chordTextcolor CSS text color for chords.
     182   */
     183  private $chordTextcolor;
     184
     185  /**
     186   * CSS text size for chords.
     187   *
     188   * @since    1.0.0
     189   * @access   private
     190   * @var      string $chordTextsize CSS text size for chords.
     191   */
     192  private $chordTextsize;
     193
     194  /**
     195   * CSS text color for lyrics.
     196   *
     197   * @since    1.0.0
     198   * @access   private
     199   * @var      string $lyricsTextcolor CSS text color for lyrics.
     200   */
     201  private $lyricsTextcolor;
     202
     203  /**
     204   * CSS text size for lyrics.
     205   *
     206   * @since    1.0.0
     207   * @access   private
     208   * @var      string $lyricsTextsize CSS text size for lyrics.
     209   */
     210  private $lyricsTextsize;
     211
     212  /**
     213   * CSS styles for lyrics.
     214   *
     215   * @since    2.3.0
     216   * @access   private
     217   * @var      string $lyricsStyle CSS styles for lyrics.
     218   */
     219  private $lyricsStyle;
     220
     221  /**
     222   * CSS styles for comments.
     223   *
     224   * @since    1.0.0
     225   * @access   private
     226   * @var      string $commentStyle CSS styles for comments.
     227   */
     228  private $commentStyle;
     229
     230  /**
     231   * CSS styles for the chords.
     232   *
     233   * @since    1.0.0
     234   * @access   private
     235   * @var      string $chordStyle CSS styles for the chorus sections.
     236   */
     237  private $chordStyle;
     238
     239  /**
     240   * CSS styles for the chorus sections.
     241   *
     242   * @since    1.0.0
     243   * @access   private
     244   * @var      string $chorusStyle CSS styles for the chorus sections.
     245   */
     246  private $chorusStyle;
     247
     248  /**
     249   * CSS styles for the verse sections.
     250   *
     251   * @since    1.0.0
     252   * @access   private
     253   * @var      string $verseStyle CSS styles for the verse sections.
     254   */
     255  private $verseStyle;
     256
     257  /**
     258   * CSS styles for the line sections.
     259   *
     260   * @since    3.1.2
     261   * @access   private
     262   * @var      string $lineStyle CSS styles for the line sections.
     263   */
     264  private $lineStyle;
     265
     266  /**
     267   * CSS float directive: no/left/right.
     268   *
     269   * @since    1.5.0
     270   * @access   private
     271   * @var      string $float CSS float directive: no/left/right.
     272   */
     273  private $float;
     274
     275  /**
     276   * Shortcode directive hbNotation: no/yes.
     277   *
     278   * @since    1.0.0
     279   * @access   private
     280   * @var      string $hbNotation Shortcode directive hbNotation: no/yes.
     281   */
     282  private $hbNotation;
     283
     284  /**
     285   * Show Chord Sheet for Vexchords.
     286   *
     287   * @since    2.1.0
     288   * @access   private
     289   * @var      string $showChordSheet Show Chord Sheet: no/yes.
     290   */
     291  private $showChordSheet;
     292
     293  /**
     294   * Show Chord Sheet on top.
     295   *
     296   * @since    2.1.0
     297   * @access   private
     298   * @var      string $showChordSheetOnTop Show Chord Sheet on top: no/yes.
     299   */
     300  private $showChordSheetOnTop;
     301
     302  /**
     303   * Shortcode directive interactive: no/yes.
     304   *
     305   * @since    1.5.0
     306   * @access   private
     307   * @var      string $interactive Shortcode directive interactive: no/yes.
     308   */
     309  private $interactive;
     310
     311  /**
     312   * Shortcode directive transpose: 0-11 (semitones).
     313   *
     314   * @since    1.0.0
     315   * @access   private
     316   * @var      string $transpose Shortcode directive transpose: 0-11 (semitones).
     317   */
     318  private $transpose;
     319
     320  /**
     321   * Array of supported ChordPro directives.
     322   *
     323   * @since    1.0.0
     324   * @access   private
     325   * @var      array $arrDirectives Array of supported ChordPro directives.
     326   */
     327  private $arrDirectives = array(
     328    'album' => '',
     329    'artist' => '',
     330    'capo' => '',
     331    'composer' => '',
     332    'key' => '',
     333    'subtitle' => '',
     334    'tempo' => '',
     335    'time' => '',
     336    'title' => '',
     337    'year' => '',
     338  );
     339
     340  /**
     341   * Array of all chords in this song.
     342   *
     343   * @since    2.1.0
     344   * @access   private
     345   * @var      array $allChords Array of all chords in this song.
     346   */
     347  private $allChords = array();
     348
     349  /**
     350   * Array of unique chords in this song.
     351   *
     352   * @since    2.1.0
     353   * @access   private
     354   * @var      array $uniqueChords Array of unique chords in this song.
     355   */
     356  private $uniqueChords = array();
     357
     358  /**
     359   * Array of supported Key directives.
     360   *
     361   * @since    3.1.0
     362   * @access   private
     363   * @var      array
     364   */
     365  private $arrKeys = array( 'A', 'Am', 'A#', 'A#m', 'Bb', 'Bbm', 'B', 'Bm', 'C', 'Cm', 'C#', 'C#m', 'Db', 'Dbm', 'D', 'Dm', 'D#', 'D#m', 'Eb', 'Ebm', 'E', 'Em', 'F', 'Fm', 'G', 'Gm', 'G#', 'G#m', 'Ab', 'Abm' );
     366
     367  /**
     368   * Array of transposed keys.
     369   *
     370   * @since    3.1.0
     371   * @access   private
     372   * @var      array
     373   */
     374  private $arrTransposeValues = array(
     375    'A' => array( 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#' ),
     376    'Am' => array( 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m' ),
     377    'A#' => array( 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A' ),
     378    'Bb' => array( 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A' ),
     379    'A#m' => array( 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am' ),
     380    'Bbm' => array( 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am' ),
     381    'B' => array( 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#' ),
     382    'Bm' => array( 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m' ),
     383    'C' => array( 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B' ),
     384    'Cm' => array( 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm' ),
     385    'C#' => array( 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C' ),
     386    'Db' => array( 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C' ),
     387    'C#m' => array( 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm' ),
     388    'Dbm' => array( 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm' ),
     389    'D' => array( 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#' ),
     390    'Dm' => array( 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m' ),
     391    'D#' => array( 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D' ),
     392    'Eb' => array( 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D' ),
     393    'D#m' => array( 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm' ),
     394    'Ebm' => array( 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm' ),
     395    'E' => array( 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#' ),
     396    'Em' => array( 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m' ),
     397    'F' => array( 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E' ),
     398    'Fm' => array( 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em' ),
     399    'F#' => array( 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F' ),
     400    'Gb' => array( 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F' ),
     401    'F#m' => array( 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm' ),
     402    'Gbm' => array( 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm' ),
     403    'G' => array( 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#' ),
     404    'Gm' => array( 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m' ),
     405    'G#' => array( 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G' ),
     406    'Ab' => array( 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G' ),
     407    'G#m' => array( 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm' ),
     408    'Abm' => array( 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm' ),
     409  );
     410
     411  /**
     412   * In monospace mode.
     413   * As long as true, lines are not analyzed, just printed out.
     414   *
     415   * @since    3.5.0
     416   * @access   private
     417   * @var      boolean $inMonospace Monospace mode flag.
     418   */
     419  private $inMonospace;
     420
     421  /**
     422   * Array of allowed prefixes for chords.
     423   *
     424   * @since    3.6.1
     425   * @access   private
     426   * @var      array
     427   */
     428  private $allowedChordPrefixes = array( '~', '|', '/', '.', '-' );
     429
     430
     431  //---------------------------------------------------------------------------
     432  /**
     433   * Initialize the class and set its properties.
     434   *
     435   * @since    1.0.0
     436   */
     437  public function __construct() {
     438    $this->C = new ChordPress_Chord();
     439    /**
     440     * Shortcode Defaults
     441     */
     442    $this->float = 'no';
     443    $this->hbNotation = 'no';
     444    $this->interactive = 'no';
     445    $this->transpose = 0;
     446    /**
     447     * Get options or set defaults
     448     */
     449    if (!$this->hideAlbum = get_option('chordpress_checkbox_hide_album')) $this->hideAlbum = 0;
     450    if (!$this->hideArtist = get_option('chordpress_checkbox_hide_artist')) $this->hideArtist = 0;
     451    if (!$this->hideChords = get_option('chordpress_checkbox_hide_chords')) $this->hideChords = 0;
     452    if (!$this->hideComments = get_option('chordpress_checkbox_hide_comments')) $this->hideComments = 0;
     453    if (!$this->hideComposer = get_option('chordpress_checkbox_hide_composer')) $this->hideComposer = 0;
     454    if (!$this->hidePrint = get_option('chordpress_checkbox_hide_print')) $this->hidePrint = 0;
     455    if (!$this->hideSubtitle = get_option('chordpress_checkbox_hide_subtitle')) $this->hideSubtitle = 0;
     456    if (!$this->hideTitle = get_option('chordpress_checkbox_hide_title')) $this->hideTitle = 0;
     457    if (!$this->hideTranspose = get_option('chordpress_checkbox_hide_transpose')) $this->hideTranspose = 0;
     458    if (!$this->hideYear = get_option('chordpress_checkbox_hide_year')) $this->hideYear = 0;
     459    if (!$this->displayHBNotation = get_option('chordpress_checkbox_hb_notation')) $this->displayHBNotation = 0;
     460    if (!$this->showChordSheet = get_option('chordpress_checkbox_show_chord_sheet')) $this->showChordSheet = 0;
     461    if (!$this->showChordSheetOnTop = get_option('chordpress_checkbox_show_chord_sheet_on_top')) $this->showChordSheetOnTop = 0;
     462    if (!$this->showNumericTranspose = get_option('chordpress_checkbox_show_numeric_transpose')) $this->showNumericTranspose = 0;
     463    if (!$this->fixedInteraction = get_option('chordpress_checkbox_fixed_interaction')) $this->fixedInteraction = 0;
     464
     465    if (!$this->titleLevel = get_option('chordpress_select_title_level')) $this->titleLevel = 'h1';
     466    if (!$this->subtitleLevel = get_option('chordpress_select_subtitle_level')) $this->subtitleLevel = 'h2';
     467    if (!$this->metaStyle = get_option('chordpress_text_meta_style')) $this->metaStyle = '';
     468    if (!$this->chordStyle = get_option('chordpress_text_chord_style')) $this->chordStyle = '';
     469    if (!$this->lyricsStyle = get_option('chordpress_text_lyrics_style')) $this->lyricsStyle = '';
     470    if (!$this->commentStyle = get_option('chordpress_text_comment_style')) $this->commentStyle = '';
     471    if (!$this->chorusStyle = get_option('chordpress_text_chorus_style')) $this->chorusStyle = '';
     472    if (!$this->verseStyle = get_option('chordpress_text_verse_style')) $this->verseStyle = '';
     473    if (!$this->lineStyle = get_option('chordpress_text_line_style')) $this->lineStyle = 'margin: 1em 0 1em 0;';
     474  }
     475
     476  //---------------------------------------------------------------------------
     477  /**
     478   * Get the ChordPro directives and store the supported ones in an array.
     479   *
     480   * @param object $text - Text inside shortcode wrapper.
     481   * @since 1.0.0
     482   */
     483  public function getDirectives($text) {
     484    foreach ($text as $line) {
     485      $line = trim($this->stripTags($line));
     486      if (strlen($line) && $line[0] == '{') {
     487        /**
     488         * Line starts with "{": It's a directive
     489         * Get directive name and value and store
     490         */
     491        $arrDirective = explode(":", $line);
     492        // $this->pretty_dump($arrDirective);
     493        $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
     494        if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
     495        /**
     496         * Process directive alternatives
     497         */
     498        switch (strtolower($directiveName)) {
     499          case "t":
     500            $directiveName = 'title';
     501            break;
     502          case "st":
     503            $directiveName = 'subtitle';
     504            break;
     505          case "meta":
     506            /**
     507             * {meta: title Heart of Gold}
     508             * We have split the "meta:" off already.
     509             * Now comes the part after.
     510             * We only handle the supported directives ($this->arrDirectives)
     511             */
     512            $arrMetaDirective = explode(" ", $directiveValue, 2);
     513            foreach ($this->arrDirectives as $key => $value) {
     514              if (trim($arrMetaDirective[0]) == $key) {
     515                $directiveName = $key;
     516                $directiveValue = trim($arrMetaDirective[1]);
     517              }
     518            }
     519            break;
     520        }
     521        /**
     522         * Store directive in directives array for later use
     523         */
     524        if (array_key_exists($directiveName, $this->arrDirectives)) {
     525          $this->arrDirectives[$directiveName] = $directiveValue;
     526        }
     527      }
     528    }
     529  }
     530
     531  //---------------------------------------------------------------------------
     532  /**
     533   * Creates the formatted HTML of the ChordPro text.
     534   *
     535   * HTML Structure
     536   *
     537   * <div class="cpress">
     538   *    <h1>{title}</h1>
     539   *    <h2>{subtitle}</h2>
     540   *    <h3>
     541   *       Album: {album}
     542   *       Artist: {artist}<br>
     543   *       Composer: {composer}<br>
     544   *       Year: {year}
     545   *    </h3>
     546   *    <div class="cpress-chorus/verse">
     547   *       <div class="cpress-line">
     548   *          <div class="cpress-line-section">
     549   *             <div class="chord">C#</div>
     550   *             <div class="lyric">Lyrics</div>
     551   *          </div>
     552   *          ...
     553   *       </div>
     554   *       ...
     555   *    </div>
     556   * </div>
     557   *
     558   * @param object $text - Text inside shortcode wrapper.
     559   * @return string - Formatted HTML of the ChordPro text.
     560   * @since 1.0.0
     561   */
     562  public function displayText($text): string {
     563    /**
     564     * Start of ChordPress wrapper
     565     */
     566    $returnText = "\n\n
     567      <!--begin: ChordPress SongSheet -->
     568      <div>
     569        <style>
     570          div.cpress { float: " . $this->float . "; }
     571          div.cpress_line { " . $this->lineStyle . "; }
     572          div.cpress_line_section { display: inline; float: left; }
     573          div.cpress_line_section .chord .chordshort { " . $this->chordStyle . "; }
     574          div.cpress_line_section .lyric { " . $this->lyricsStyle . "; }
     575          div.cpress_chorus { " . $this->chorusStyle . "; }
     576          div.cpress_verse { " . $this->verseStyle . "; }
     577          div.cpress_clear { clear: both; }
     578          div.cpress_meta { " . $this->metaStyle . "; }
     579          div.cpress_interaction { float: right; }
     580          div.cpress_interaction select { width: auto; }
     581          span.cpress_comment { " . $this->commentStyle . "; }
     582          div.cpress_chordsheet { text-align: center; }
     583        </style>
     584      </div>\n";
     585
     586    /**
     587     * Interaction menu
     588     */
     589    if (in_array(strtolower($this->interactive), array( "yes", "1", "true" ))) {
     590      $interactionForm = "<div class=\"cpress-interaction cpress-row";
     591      if ($this->fixedInteraction) {
     592        $interactionForm .= " fixed";
     593      }
     594      $interactionForm .= "\">";
     595      $interactionForm .= "<div class='cpress-col cpress-pl-0'>" . __('Font', 'chordpress') . "
     596          <div class='cpress-btn-group' role='group'>
     597            <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', -5);\">-</button>
     598            <button id=\"btnFontSize-%cpressID%\"  type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 0);\">100%</button>
     599            <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 5);\">+</button>
     600          </div>
     601        </div>";
     602      if (!$this->hideTranspose) {
     603        $interactionForm .= "<div class='cpress-col cpress-text-center' style='display: inline-block;'>";
     604        if ($this->showNumericTranspose) {
     605          $interactionForm .= "<span class=''>" . __('Transpose', 'chordpress') . "</span>
     606            <div class='cpress-btn-group' role='group'>
     607              <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'down');\">-</button>
     608              <button id=\"btnTranspose-%cpressID%\" type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'reset');\" value='0'>0</button>
     609              <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'up');\">+</button>
     610            </div>";
     611        } else {
     612          //
     613          // Let's see if a 'Key' directive was given. If so, we can add
     614          // the transposed keys to the list.
     615          //
     616          if (strlen($this->arrDirectives['key']) && in_array($this->arrDirectives['key'], $this->arrKeys)) {
     617            $i = 0;
     618            foreach ($this->arrTransposeValues[$this->arrDirectives['key']] as $val) {
     619              $tvalues[] = (string)$i . ' => ' . $val;
     620              $i++;
     621            }
     622          } else {
     623            $tvalues = array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11' );
     624          }
     625          $interactionForm .= __('Transpose', 'chordpress') . "
     626            <select class=\"cpress-form-control cpress-form-control-sm cpress-w-50 cpress-py-0 cpress-px-2 float-right\" id=\"selTranspose-%cpressID%\" onchange=\"transposeChords('%cpressID%', 'selTranspose-');return false;\" title=\"" . __('Only works for international key names', 'chordpress') . ".\">
     627              <option value=\"0\">" . $tvalues[0] . "</option>
     628              <option value=\"1\">" . $tvalues[1] . "</option>
     629              <option value=\"2\">" . $tvalues[2] . "</option>
     630              <option value=\"3\">" . $tvalues[3] . "</option>
     631              <option value=\"4\">" . $tvalues[4] . "</option>
     632              <option value=\"5\">" . $tvalues[5] . "</option>
     633              <option value=\"6\">" . $tvalues[6] . "</option>
     634              <option value=\"7\">" . $tvalues[7] . "</option>
     635              <option value=\"8\">" . $tvalues[8] . "</option>
     636              <option value=\"9\">" . $tvalues[9] . "</option>
     637              <option value=\"10\">" . $tvalues[10] . "</option>
     638              <option value=\"11\">" . $tvalues[11] . "</option>
     639            </select>";
     640        }
     641        $interactionForm .= "</div>";
     642      }
     643      $interactionForm .= "<div class='cpress-col cpress-text-end cpress-pr-0'>";
     644      if (!$this->hidePrint) {
     645        $interactionForm .= "<button class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"window.print();\">" . __('Print', 'chordpress') . "</button>\n";
     646      }
     647      $interactionForm .= "</div>";
     648      $returnText .= $interactionForm . "</div>\n";
     649    }
     650
     651    $returnText .= "<div id=\"%cpressID%\" class=\"cpress\">\n";
     652
     653    /**
     654     * Print header if directives exist
     655     */
     656    $randId = $this->random_string(true);
     657    if (strlen($this->arrDirectives['title']) && !$this->hideTitle) {
     658      $cpressID = str_replace(' ', '-', strtolower(trim($this->arrDirectives['title']))) . '-' . $randId;
     659      $returnText = str_replace('%cpressID%', $cpressID, $returnText);
     660      $returnText .= '<' . $this->titleLevel . '>' . $this->arrDirectives['title'] . '</' . $this->titleLevel . ">\n";
     661    } else {
     662      $cpressID = 'ccpress-id-' . $randId;
     663      $returnText = str_replace('%cpressID%', $cpressID, $returnText);
     664    }
     665
     666    if (strlen($this->arrDirectives['subtitle']) && !$this->hideSubtitle) {
     667      $returnText .= '<' . $this->subtitleLevel . '>' . $this->arrDirectives['subtitle'] . '</' . $this->subtitleLevel . ">\n";
     668    }
     669
     670    if (
     671      strlen($this->arrDirectives['album']) ||
     672      strlen($this->arrDirectives['artist']) ||
     673      strlen($this->arrDirectives['capo']) ||
     674      strlen($this->arrDirectives['composer']) ||
     675      strlen($this->arrDirectives['key']) ||
     676      strlen($this->arrDirectives['tempo']) ||
     677      strlen($this->arrDirectives['time']) ||
     678      strlen($this->arrDirectives['year'])
     679    ) {
     680      $returnText .= "<div class=\"cpress_meta\">\n";
     681      if (strlen($this->arrDirectives['composer']) && !$this->hideComposer) $returnText .= esc_html(__('Composer', 'chordpress')) . ': ' . $this->arrDirectives['composer'] . "<br>\n";
     682      if (strlen($this->arrDirectives['artist']) && !$this->hideArtist) $returnText .= esc_html(__('Artist', 'chordpress')) . ': ' . $this->arrDirectives['artist'] . "<br>\n";
     683      if (strlen($this->arrDirectives['year']) && !$this->hideYear) $returnText .= esc_html(__('Year', 'chordpress')) . ': ' . $this->arrDirectives['year'] . "<br>\n";
     684      if (strlen($this->arrDirectives['album']) && !$this->hideAlbum) $returnText .= esc_html(__('Album', 'chordpress')) . ': ' . $this->arrDirectives['album'] . "<br>\n";
     685
     686      if (strlen($this->arrDirectives['key'])) {
     687        $returnText .= esc_html(__('Key (original)', 'chordpress')) . ': ' . $this->arrDirectives['key'] . "<br>\n";
     688        $returnText .= esc_html(__('Key (transposed)', 'chordpress')) . ': <span class="chord-hidable-%cpressID% key-%cpressID%-0">' . $this->arrDirectives['key'] . '</span>';
     689        for ($t = 1; $t <= 11; $t++) {
     690          $returnText .= '<span class="chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none">' . $this->arrTransposeValues[$this->arrDirectives['key']][$t] . '</span>';
     691        }
     692        $returnText .= "<br>\n";
     693      }
     694
     695      if (strlen($this->arrDirectives['time'])) $returnText .= esc_html(__('Time', 'chordpress')) . ': ' . $this->arrDirectives['time'] . "<br>\n";
     696      if (strlen($this->arrDirectives['tempo'])) $returnText .= esc_html(__('Tempo', 'chordpress')) . ': ' . $this->arrDirectives['tempo'] . "<br>\n";
     697      if (strlen($this->arrDirectives['capo'])) $returnText .= esc_html(__('Capo', 'chordpress')) . ': ' . $this->arrDirectives['capo'] . "<br>\n";
     698      $returnText = preg_replace('/<br>$/', '', $returnText); // Remove last <br>
     699      $returnText .= "</div>\n";
     700    }
     701
     702    /**
     703     * Go through each line and process it
     704     */
     705    $this->inMonospace = false;
     706//        $this->C->dnd($text, false);
     707    foreach ($text as $line) {
     708      if ($this->inMonospace && strpos($line, "{end_of_monospace}") === false) {
     709        $returnText .= $line;
     710      } else {
     711//                $this->C->dnd("IN: " . $line, false);
     712        $returnText .= $this->formatAndDisplayLine($line);
     713//                $this->C->dnd("OUT: " . $returnText, false);
     714      }
     715    }
     716    $returnText = str_replace('%cpressID%', $cpressID, $returnText);
     717//        $this->C->dnd($returnText, false);
     718
     719    /**
     720     * End of ChordPress song
     721     */
     722    $returnText .= "</div>\n<!--end: ChordPress SongSheet-->\n";
     723
     724    /**
     725     * Build chord sheet if option set to true.
     726     */
     727    if ($this->showChordSheet) {
     728      $chordSheetText = "\n<!--begin: ChordPress ChordSheet-->\n";
     729      $chordSheetText .= "<div class='cpress_chordsheet'>\n";
     730      $chordSheetText .= "<div><hr></div>\n";
     731      $chordSheetText .= "<p><i>" . esc_html(__('These known chords are used in this song', 'chordpress')) . ".</i></p>";
     732      $this->uniqueChords = array_unique($this->allChords);
     733      foreach ($this->uniqueChords as $uc) {
     734        if ($postid = $this->find_guitar_chord_post($uc)) {
     735          $this->load_guitar_chord($postid);
     736          $chordSheetText .= $this->C->createSvgChord(true);
     737        }
     738      }
     739      $chordSheetText .= "</div>\n<div style=\"clear:both; padding: 16px 0 16px 0;\"><hr></div>\n<!--end: ChordPress ChordSheet-->\n\n";
     740      if ($this->showChordSheetOnTop) {
     741        $returnText = $chordSheetText . $returnText;
     742      } else {
     743        $returnText = $returnText . $chordSheetText;
     744      }
     745    }
     746
     747    // $this->C->dnd($returnText);
     748    return $returnText . "\n\n";
     749  }
     750
     751  //---------------------------------------------------------------------------
     752  /**
     753   * Process a single of the ChordPro text and return the formatted HTML.
     754   *
     755   * @param string $line - Single line from inside shortcode wrapper.
     756   * @return string - Formatted HTML.
     757   * @since 1.0.0
     758   */
     759  public function formatAndDisplayLine($line) {
     760    $returnText = "";
     761
     762    /**
     763     * Array of chords
     764     */
     765    $arrChords = array();
     766
     767    /**
     768     * Array of corresponding lyrics starting at a chord and ending prior
     769     * to the next chord or the end-of-line.
     770     */
     771    $arrLyrics = array();
     772
     773    /**
     774     * Now check what this line is all about
     775     */
     776    if (substr_count($line, "[") == 0) {
     777      /**
     778       * No chords on this line
     779       */
     780      if (isset($line[0]) && ($line[0] == '#' || $line == '<br />')) {
     781        /**
     782         * Line starts with "#": It's a comment line => return empty string
     783         */
     784        return "";
     785      } else if ((isset($line[0]) && $line[0] == '{') || (isset($line[0]) && strpos($line, '{'))) {
     786        /**
     787         * Line starts with "{" or has one in it: It's a directive
     788         * Some of them need consideration for the output
     789         */
     790        $directive = strstr($line, '{'); // Remove all before the {
     791        $arrDirective = explode(":", $directive);
     792        $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
     793        if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
     794
     795        /**
     796         * In case the directive had no colon and value, $directiveName will
     797         * still contain the trailing }. So let's remove that.
     798         */
     799        if (substr_count($directiveName, "}")) $directiveName = str_replace("}", "", $directiveName);
     800
     801        if (strpos($directiveName, 'start_of_verse') !== false) {
     802          return "<div class=\"cpress_verse\">\n<div class=\"cpress_line\">\n";
     803        } elseif (strpos($directiveName, 'end_of_verse') !== false) {
     804          return "</div></div>\n";
     805        } elseif (strpos($directiveName, 'start_of_chorus') !== false) {
     806          return "<div class=\"cpress_chorus\">\n<div class=\"cpress_line\">\n";
     807        } elseif (strpos($directiveName, 'end_of_chorus') !== false) {
     808          return "</div></div>\n";
     809        } elseif (strpos($directiveName, 'start_of_monospace') !== false) {
     810          $this->inMonospace = true;
     811          return "<pre>\n";
     812        } elseif (strpos($directiveName, 'end_of_monospace') !== false) {
     813          $this->inMonospace = false;
     814          return "</pre>\n";
     815        } elseif (
     816          strpos($directiveName, 'title') !== false ||
     817          strpos($directiveName, 'subtitle') !== false ||
     818          strpos($directiveName, 'album') !== false ||
     819          strpos($directiveName, 'artist') !== false ||
     820          strpos($directiveName, 'capo') !== false ||
     821          strpos($directiveName, 'composer') !== false ||
     822          strpos($directiveName, 'key') !== false ||
     823          strpos($directiveName, 'tempo') !== false ||
     824          strpos($directiveName, 'time') !== false ||
     825          strpos($directiveName, 'year') !== false ||
     826          strpos($directiveName, 'artist') !== false
     827        ) {
     828          //
     829          // We have already processed these directives. Just return empty for this line.
     830          //
     831          return "";
     832        } elseif (strpos($directiveName, 'comment') !== false && !$this->hideComments) {
     833          $arrLyrics[] = '<span class="cpress_comment">' . $directiveValue . '</span>';
     834        }
     835      } else {
     836        /**
     837         * Just lyrics without chords => print it
     838         */
     839        $arrLyrics[] = $line;
     840      }
     841    } elseif (substr_count($line, "[") != substr_count($line, "]")) {
     842      /**
     843       * Square bracket missing in this line
     844       */
     845      $arrLyrics[] = '<span style="color:#FF0000;"><i>' . esc_html(__('Missing square bracket in line', 'chordpress')) . ':</i></span> <code>' . $line . "</code>";
     846    } else {
     847      /**
     848       * Chords found. Split the line into segments beginning with '['
     849       */
     850      $arrBracketSegments = explode("[", $line);
     851      foreach ($arrBracketSegments as $segment) {
     852        if (strlen($segment)) {
     853          $pad = ($segment[strlen($segment) - 1] == ' ') ? '&nbsp;' : '';
     854          /**
     855           * Does the first segment start before the 1st '['?
     856           */
     857          if (substr_count($segment, "]") == 0) {
     858            $arrChords[] = " ";
     859            $arrLyrics[] = $segment . $pad;
     860          } else {
     861            /**
     862             * Split this segment into chord an lyrics
     863             */
     864            $arrChordLyric = explode("]", $segment);
     865            $arrChords[] = trim($arrChordLyric[0]);
     866            $arrLyrics[] = $arrChordLyric[1] . $pad;
     867          }
     868        }
     869      }
     870    }
     871
     872    /**
     873     * Start of line wrapper (lyrics and chords)
     874     */
     875    $returnText .= "<div class=\"cpress_line\">\n";
     876
     877    /**
     878     * Align chords and lyrics together by wrapping each in a floating inline div
     879     */
     880    if (!$this->hideChords) {
     881
     882      for ($i = 0; $i < count($arrChords); $i++) {
     883
     884        if (strlen(trim($arrChords[$i])) > 0 || strlen(trim($arrLyrics[$i])) > 0) {
     885
     886          $lyrics = trim($this->stripTags($arrLyrics[$i]));
     887
     888          /**
     889           * Start of line-section (one chord and its lyrics)
     890           */
     891          $returnText .= "<div class=\"cpress_line_section\">\n";
     892
     893          if (strlen(trim($arrChords[$i])) > 0) {
     894
     895            $returnText .= "<div class=\"chord chord-hidable-%cpressID% key-%cpressID%-0\"><span class=\"chordshort\">";
     896
     897            /**
     898             * Allow chords starting with a ~, |, / and . as chord placeholders. Just return the string.
     899             * Att: ... will end up as &ellip; . Use blanks between each dot.
     900             */
     901            if (in_array($arrChords[$i][0], $this->allowedChordPrefixes)) {
     902              $returnText .= $arrChords[$i];
     903            } else {
     904              $theChord = $this->formatChord($arrChords[$i]);
     905              $this->allChords[] = $theChord;
     906              $returnText .= $theChord;
     907            }
     908
     909            $returnText .= "</span>&nbsp;</div>\n";
     910
     911            /**
     912             * Prepare all other 11 transposed versions of the chord
     913             * but hide them. They need to be on the page for interactive
     914             * mode to show/hide them via Javascript.
     915             * But do not mark empty chord divs as hidable. They need to stay.
     916             */
     917            $returnText .= "\n";
     918            $tempTranspose = $this->getTranspose();
     919
     920            for ($t = 1; $t <= 11; $t++) {
     921              $this->setTranspose($t);
     922              /**
     923               * Allow chords starting with a special characters, e.g. ~ as chord placeholders.
     924               * Just return the string.
     925               */
     926              if (in_array($arrChords[$i][0], $this->allowedChordPrefixes)) {
     927                $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $arrChords[$i] . '</span>&nbsp;</div>';
     928                $returnText .= "\n";
     929              } else {
     930                /**
     931                 * This is a real chord.
     932                 */
     933                $theChord = $this->formatChord($arrChords[$i]);
     934                $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $theChord . '</span>&nbsp;</div>';
     935              }
     936            }
     937
     938            $this->setTranspose($tempTranspose);
     939
     940            /**
     941             * Now add the lyrics for this section.
     942             */
     943            $returnText .= '<div class="lyric">';
     944
     945            if (strlen($lyrics) > 0) {
     946              $endOf1stWord = strpos($lyrics, ' ');
     947              $numSpaces = substr_count($lyrics, ' ');
     948              if ($endOf1stWord > 0 && $numSpaces == 1) {
     949                $returnText .= substr($lyrics, 0, $endOf1stWord) . '&nbsp;';
     950                $lyrics = substr($lyrics, $endOf1stWord);
     951                $returnText .= "</div></div>\n<div class=\"cpress_line_section\">\n<div class=\"chord\">&nbsp;</div><div class=\"lyric\">";
     952              }
     953            }
     954          } else {
     955            $returnText .= '<div class="chord">&nbsp;</div>';
     956            $returnText .= '<div class="lyric">';
     957          }
     958
     959          if (strlen($lyrics) > 0) $returnText .= $lyrics;
     960          $returnText .= "</div>\n"; // end of lyric
     961          $returnText .= "</div>\n"; // end of line
     962
     963        }
     964      }
     965
     966      /**
     967       * If there are more lyric parts than chord parts, add them here
     968       */
     969      for ($i = count($arrChords); $i < count($arrLyrics); $i++) {
     970        $returnText .= $arrLyrics[$i];
     971      }
     972    } else {
     973
     974      /**
     975       * Hide chords was selected, so only show the lyrics
     976       */
     977      $returnText .= '<div class="cpress_line_section"><div class="lyric">';
     978
     979      for ($i = 0; $i < count($arrLyrics); $i++) {
     980        $returnText .= $arrLyrics[$i];
     981      }
     982
     983      $returnText .= "</div></div>";
     984    }
     985
     986    /**
     987     * End of line wrapper
     988     */
     989    $returnText .= "</div>\n";
     990
     991    /**
     992     * Add a clear:both div
     993     */
     994    $returnText .= "<div class='cpress_clear'></div>\n";
     995
     996    return $returnText;
     997  }
     998
     999  //---------------------------------------------------------------------------
     1000  /**
     1001   * Remove all <> wrapped text from a string.
     1002   *
     1003   * @param string $string - String to process.
     1004   * @return string - Stripped text.
     1005   * @since 1.0.0
     1006   */
     1007  private function stripTags($string) {
     1008    $retString = "";
     1009    $isVisible = true;
     1010    for ($i = 0; $i < strlen($string); $i++) {
     1011      if ($isVisible) {
     1012        if ($string[$i] == '<')
     1013          $isVisible = false;
     1014        else
     1015          $retString .= $string[$i];
     1016      } elseif ($string[$i] == '>') {
     1017        $isVisible = true;
     1018      }
     1019    }
     1020    return $retString;
     1021  }
     1022
     1023  //---------------------------------------------------------------------------
     1024  /**
     1025   * Processes a note text and returns the formatted HTML.
     1026   *
     1027   * @param string $ch - Chord text, e.g. "A" or "B#" or "Db/F" or "IV".
     1028   * @return string - Uppercase note string.
     1029   * @since 1.0.0
     1030   */
     1031  public function formatChord($ch) {
     1032    $useFlats = false;
     1033    if (strlen($ch) == 0) return '';
     1034
     1035    /**
     1036     * Return other valid chord identifiers as is
     1037     */
     1038    $italianChords = array( 'Do', 'do', 'Re', 're', 'Mi', 'mi', 'Fa', 'fa', 'Sol', 'sol', 'La', 'la', 'Si', 'si' );
     1039    $nashvilleChords = array( '1', '2', '3', '4', '5', '6', '7' );
     1040    $romanChords = array( 'I', 'I7', 'II', 'III', 'iii', 'IV', 'V', 'V7', 'VI', 'vi', 'VI7', 'vi7', 'VII' );
     1041    if (in_array($ch, $italianChords) or in_array($ch, $nashvilleChords) or in_array($ch, $romanChords)) return $ch;
     1042
     1043    /**
     1044     * The first letter should be the key note
     1045     */
     1046    $note = substr($ch, 0, 1);
     1047    $rem = substr($ch, 1);
     1048
     1049    /**
     1050     * Convert note to a number
     1051     */
     1052    $noteVal = $this->noteToNumber($note);
     1053
     1054    /**
     1055     * Check sharp/flat
     1056     */
     1057    if (strlen($rem) > 0) {
     1058      if (substr($rem, 0, 1) == '#') {
     1059        $noteVal++;
     1060        $rem = substr($rem, 1);
     1061      } elseif (strncasecmp($rem, "b", 1) == 0) {
     1062        $useFlats = true;
     1063        $noteVal--;
     1064        $rem = substr($rem, 1);
     1065      }
     1066    }
     1067
     1068    /**
     1069     * Add transpose
     1070     */
     1071    $noteVal += $this->transpose;
     1072    if ($noteVal > 11) $noteVal -= 12;
     1073    if ($noteVal < 0) $noteVal += 12;
     1074
     1075    /**
     1076     * Build note to display from numeric note value
     1077     */
     1078    $xlatedNote = $this->numberToNote($noteVal, $useFlats);
     1079    // die($this->pretty_dump($xlatedNote));
     1080
     1081    /**
     1082     * Return the chord display plus the bass note (if any)
     1083     */
     1084    return $xlatedNote . $this->formatRemainder($rem);
     1085  }
     1086
     1087  //---------------------------------------------------------------------------
     1088  /**
     1089   * Process the remainder of the given chord.
     1090   *
     1091   * @param string $remainder - Chord text starting at second char.
     1092   * @return string - Formatted remainder.
     1093   * @since 1.0.0
     1094   */
     1095  public function formatRemainder($remainder) {
     1096    $indexOfSlash = strpos($remainder, '/');
     1097    if ($indexOfSlash === false) return $remainder;
     1098
     1099    /**
     1100     * We have a slash, indicating that a bass note follows.
     1101     * Break the string into 2 parts at the slash.
     1102     * The slash will be lost, and will need to be added back later.
     1103     */
     1104    $chord = substr($remainder, 0, $indexOfSlash);
     1105    $bass = substr($remainder, $indexOfSlash + 1);
     1106
     1107    $useFlats = false;
     1108
     1109    if (strlen($bass) == 0) return $chord . "/?";
     1110
     1111    /**
     1112     * The first letter should be the bass note
     1113     */
     1114    $note = substr($bass, 0, 1);
     1115    $xlatedNote = $note;
     1116    $rem = substr($bass, 1);
     1117
     1118    /**
     1119     * Convert note to a number
     1120     */
     1121    $noteVal = $this->noteToNumber($note);
     1122
     1123    /**
     1124     * Check sharp/flat
     1125     */
     1126    if (strlen($rem) > 0) {
     1127      if (substr($rem, 0, 1) == '#') {
     1128        $noteVal++;
     1129        $rem = substr($rem, 1);
     1130      } elseif (strncasecmp($rem, "b", 1) == 0) {
     1131        $useFlats = true;
     1132        $noteVal--;
     1133        $rem = substr($rem, 1);
     1134      }
     1135    }
     1136
     1137    /**
     1138     * Add transpose
     1139     */
     1140    $noteVal += $this->transpose;
     1141    if ($noteVal > 11) $noteVal -= 12;
     1142    if ($noteVal < 0) $noteVal += 12;
     1143
     1144    /**
     1145     * Build note to display from numeric note value
     1146     */
     1147    $xlatedNote = $this->numberToNote($noteVal);
     1148
     1149    return $chord . "/" . $xlatedNote . $rem;
     1150  }
     1151
     1152  //---------------------------------------------------------------------------
     1153  /**
     1154   * Convert note to number.
     1155   *
     1156   * @param string $n - Note to convert.
     1157   * @return integer
     1158   * @since 1.0.0
     1159   */
     1160  public function noteToNumber($n) {
     1161    $regularNotation = array(
     1162      'A' => 0,
     1163      'B' => 2,
     1164      'C' => 3,
     1165      'D' => 5,
     1166      'E' => 7,
     1167      'F' => 8,
     1168      'G' => 10,
    3391169    );
    3401170
    341     /**
    342      * Array of all chords in this song.
    343      *
    344      * @since    2.1.0
    345      * @access   private
    346      * @var      array $allChords Array of all chords in this song.
    347      */
    348     private $allChords = array();
    349 
    350     /**
    351      * Array of unique chords in this song.
    352      *
    353      * @since    2.1.0
    354      * @access   private
    355      * @var      array $uniqueChords Array of unique chords in this song.
    356      */
    357     private $uniqueChords = array();
    358 
    359     /**
    360      * Array of supported Key directives.
    361      *
    362      * @since    3.1.0
    363      * @access   private
    364      * @var      array
    365      */
    366     private $arrKeys = array('A', 'Am', 'A#', 'A#m', 'Bb', 'Bbm', 'B', 'Bm', 'C', 'Cm', 'C#', 'C#m', 'Db', 'Dbm', 'D', 'Dm', 'D#', 'D#m', 'Eb', 'Ebm', 'E', 'Em', 'F', 'Fm', 'G', 'Gm', 'G#', 'G#m', 'Ab', 'Abm');
    367 
    368     /**
    369      * Array of transposed keys.
    370      *
    371      * @since    3.1.0
    372      * @access   private
    373      * @var      array
    374      */
    375     private $arrTransposeValues = array(
    376         'A' => array('A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'),
    377         'Am' => array('Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m'),
    378         'A#' => array('A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A'),
    379         'Bb' => array('Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A'),
    380         'A#m' => array('A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am'),
    381         'Bbm' => array('Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am'),
    382         'B' => array('B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#'),
    383         'Bm' => array('Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m'),
    384         'C' => array('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'),
    385         'Cm' => array('Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm'),
    386         'C#' => array('C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C'),
    387         'Db' => array('Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C'),
    388         'C#m' => array('C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm'),
    389         'Dbm' => array('Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm'),
    390         'D' => array('D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#'),
    391         'Dm' => array('Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m'),
    392         'D#' => array('D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D'),
    393         'Eb' => array('Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D'),
    394         'D#m' => array('D#m', 'Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm'),
    395         'Ebm' => array('Ebm', 'Em', 'Fm', 'Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm'),
    396         'E' => array('E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#'),
    397         'Em' => array('Em', 'Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m'),
    398         'F' => array('F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E'),
    399         'Fm' => array('Fm', 'F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em'),
    400         'F#' => array('F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F'),
    401         'Gb' => array('Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F'),
    402         'F#m' => array('F#m', 'Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm'),
    403         'Gbm' => array('Gbm', 'Gm', 'Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm'),
    404         'G' => array('G', 'G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#'),
    405         'Gm' => array('Gm', 'G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m'),
    406         'G#' => array('G#', 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G'),
    407         'Ab' => array('Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G'),
    408         'G#m' => array('G#m', 'Am', 'A#m', 'Bm', 'Cm', 'C#m', 'Dm', 'D#m', 'Em', 'Fm', 'F#m', 'Gm'),
    409         'Abm' => array('Abm', 'Am', 'Bbm', 'Bm', 'Cm', 'Dbm', 'Dm', 'Ebm', 'Em', 'Fm', 'Gbm', 'Gm'),
     1171    $hbNotation = array(
     1172      'A' => 0,
     1173      'B' => 1,
     1174      'H' => 2,
     1175      'C' => 3,
     1176      'D' => 5,
     1177      'E' => 7,
     1178      'F' => 8,
     1179      'G' => 10,
    4101180    );
    4111181
    412     /**
    413      * In monospace mode.
    414      * As long as true, lines are not analyzed, just printed out.
    415      *
    416      * @since    3.5.0
    417      * @access   private
    418      * @var      boolean $inMonospace Monospace mode flag.
    419      */
    420     private $inMonospace;
    421 
    422     //--------------------------------------------------------------------------
    423 
    424     /**
    425      * Initialize the class and set its properties.
    426      *
    427      * @since    1.0.0
    428      */
    429     public function __construct()
    430     {
    431         $this->C = new ChordPress_Chord();
    432         /**
    433          * Shortcode Defaults
    434          */
    435         $this->float = 'no';
    436         $this->hbNotation = 'no';
    437         $this->interactive = 'no';
    438         $this->transpose = 0;
    439         /**
    440          * Get options or set defaults
    441          */
    442         if (!$this->hideAlbum = get_option('chordpress_checkbox_hide_album')) $this->hideAlbum = 0;
    443         if (!$this->hideArtist = get_option('chordpress_checkbox_hide_artist')) $this->hideArtist = 0;
    444         if (!$this->hideChords = get_option('chordpress_checkbox_hide_chords')) $this->hideChords = 0;
    445         if (!$this->hideComments = get_option('chordpress_checkbox_hide_comments')) $this->hideComments = 0;
    446         if (!$this->hideComposer = get_option('chordpress_checkbox_hide_composer')) $this->hideComposer = 0;
    447         if (!$this->hidePrint = get_option('chordpress_checkbox_hide_print')) $this->hidePrint = 0;
    448         if (!$this->hideSubtitle = get_option('chordpress_checkbox_hide_subtitle')) $this->hideSubtitle = 0;
    449         if (!$this->hideTitle = get_option('chordpress_checkbox_hide_title')) $this->hideTitle = 0;
    450         if (!$this->hideTranspose = get_option('chordpress_checkbox_hide_transpose')) $this->hideTranspose = 0;
    451         if (!$this->hideYear = get_option('chordpress_checkbox_hide_year')) $this->hideYear = 0;
    452         if (!$this->displayHBNotation = get_option('chordpress_checkbox_hb_notation')) $this->displayHBNotation = 0;
    453         if (!$this->showChordSheet = get_option('chordpress_checkbox_show_chord_sheet')) $this->showChordSheet = 0;
    454         if (!$this->showChordSheetOnTop = get_option('chordpress_checkbox_show_chord_sheet_on_top')) $this->showChordSheetOnTop = 0;
    455         if (!$this->showNumericTranspose = get_option('chordpress_checkbox_show_numeric_transpose')) $this->showNumericTranspose = 0;
    456         if (!$this->fixedInteraction = get_option('chordpress_checkbox_fixed_interaction')) $this->fixedInteraction = 0;
    457 
    458         if (!$this->titleLevel = get_option('chordpress_select_title_level')) $this->titleLevel = 'h1';
    459         if (!$this->subtitleLevel = get_option('chordpress_select_subtitle_level')) $this->subtitleLevel = 'h2';
    460         if (!$this->metaStyle = get_option('chordpress_text_meta_style')) $this->metaStyle = '';
    461         if (!$this->chordStyle = get_option('chordpress_text_chord_style')) $this->chordStyle = '';
    462         if (!$this->lyricsStyle = get_option('chordpress_text_lyrics_style')) $this->lyricsStyle = '';
    463         if (!$this->commentStyle = get_option('chordpress_text_comment_style')) $this->commentStyle = '';
    464         if (!$this->chorusStyle = get_option('chordpress_text_chorus_style')) $this->chorusStyle = '';
    465         if (!$this->verseStyle = get_option('chordpress_text_verse_style')) $this->verseStyle = '';
    466         if (!$this->lineStyle = get_option('chordpress_text_line_style')) $this->lineStyle = 'margin: 1em 0 1em 0;';
    467     }
    468 
    469     //--------------------------------------------------------------------------
    470 
    471     /**
    472      * Get the ChordPro directives and store the supported ones in an array.
    473      *
    474      * @param object $text - Text inside shortcode wrapper.
    475      * @since 1.0.0
    476      */
    477     public function getDirectives($text)
    478     {
    479         foreach ($text as $line) {
    480             $line = trim($this->stripTags($line));
    481             if (strlen($line) && $line[0] == '{') {
    482                 /**
    483                  * Line starts with "{": It's a directive
    484                  * Get directive name and value and store
    485                  */
    486                 $arrDirective = explode(":", $line);
    487                 // $this->pretty_dump($arrDirective);
    488                 $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
    489                 if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
    490                 /**
    491                  * Process directive alternatives
    492                  */
    493                 switch (strtolower($directiveName)) {
    494                     case "t":
    495                         $directiveName = 'title';
    496                         break;
    497                     case "st":
    498                         $directiveName = 'subtitle';
    499                         break;
    500                     case "meta":
    501                         /**
    502                          * {meta: title Heart of Gold}
    503                          * We have split the "meta:" off already.
    504                          * Now comes the part after.
    505                          * We only handle the supported directives ($this->arrDirectives)
    506                          */
    507                         $arrMetaDirective = explode(" ", $directiveValue, 2);
    508                         foreach ($this->arrDirectives as $key => $value) {
    509                             if (trim($arrMetaDirective[0]) == $key) {
    510                                 $directiveName = $key;
    511                                 $directiveValue = trim($arrMetaDirective[1]);
    512                             }
    513                         }
    514                         break;
    515                 }
    516                 /**
    517                  * Store directive in directives array for later use
    518                  */
    519                 if (array_key_exists($directiveName, $this->arrDirectives)) {
    520                     $this->arrDirectives[$directiveName] = $directiveValue;
    521                 }
    522             }
     1182    if (in_array(strtolower($this->hbNotation), array( "yes", "1", "true" ))) {
     1183      if (array_key_exists(strtoupper($n), $hbNotation)) {
     1184        return $hbNotation[strtoupper($n)];
     1185      } else {
     1186        return 0;
     1187      }
     1188    } else {
     1189      if (array_key_exists(strtoupper($n), $regularNotation)) {
     1190        return $regularNotation[strtoupper($n)];
     1191      } else {
     1192        return 0;
     1193      }
     1194    }
     1195  }
     1196
     1197  //---------------------------------------------------------------------------
     1198  /**
     1199   * Convert number to note.
     1200   *
     1201   * @param integer $n - Numeric note value to convert to note string.
     1202   * @param boolean $useFlats - Whether to use flat notes or not.
     1203   * @return string
     1204   * @since 1.0.0
     1205   */
     1206  public function numberToNote($n, $useFlats = false) {
     1207    $retVal = '';
     1208
     1209    switch ($n) {
     1210      case 0:
     1211        $retVal = 'A';
     1212        break;
     1213      case 1:
     1214        if ($this->displayHBNotation) {
     1215          $retVal = 'B';
     1216        } else {
     1217          if ($useFlats) $retVal = "Bb";
     1218          else $retVal = "A#";
    5231219        }
    524     }
    525 
    526     //--------------------------------------------------------------------------
    527 
    528     /**
    529      * Creates the formatted HTML of the ChordPro text.
    530      *
    531      * HTML Structure
    532      *
    533      * <div class="cpress">
    534      *    <h1>{title}</h1>
    535      *    <h2>{subtitle}</h2>
    536      *    <h3>
    537      *       Album: {album}
    538      *       Artist: {artist}<br>
    539      *       Composer: {composer}<br>
    540      *       Year: {year}
    541      *    </h3>
    542      *    <div class="cpress-chorus/verse">
    543      *       <div class="cpress-line">
    544      *          <div class="cpress-line-section">
    545      *             <div class="chord">C#</div>
    546      *             <div class="lyric">Lyrics</div>
    547      *          </div>
    548      *          ...
    549      *       </div>
    550      *       ...
    551      *    </div>
    552      * </div>
    553      *
    554      * @param object $text - Text inside shortcode wrapper.
    555      * @return string - Formatted HTML of the ChordPro text.
    556      * @since 1.0.0
    557      */
    558     public function displayText($text): string
    559     {
    560         /**
    561          * Start of ChordPress wrapper
    562          */
    563         $returnText = "\n\n
    564         <!--begin: ChordPress SongSheet -->
    565         <div>
    566             <style>
    567                 div.cpress { float: " . $this->float . "; }
    568                 div.cpress_line { " . $this->lineStyle . "; }
    569                 div.cpress_line_section { display: inline; float: left; }
    570                 div.cpress_line_section .chord .chordshort { " . $this->chordStyle . "; }
    571                 div.cpress_line_section .lyric { " . $this->lyricsStyle . "; }
    572                 div.cpress_chorus { " . $this->chorusStyle . "; }
    573                 div.cpress_verse { " . $this->verseStyle . "; }
    574                 div.cpress_clear { clear: both; }
    575                 div.cpress_meta { " . $this->metaStyle . "; }
    576                 div.cpress_interaction { float: right; }
    577                 div.cpress_interaction select { width: auto; }
    578                 span.cpress_comment { " . $this->commentStyle . "; }
    579                 div.cpress_chordsheet { text-align: center; }
    580             </style>
    581         </div>\n";
    582 
    583         /**
    584          * Interaction menu
    585          */
    586         if (in_array(strtolower($this->interactive), array("yes", "1", "true"))) {
    587             $interactionForm = "<div class=\"cpress-interaction cpress-row";
    588             if ($this->fixedInteraction) {
    589                 $interactionForm .= " fixed";
    590             }
    591             $interactionForm .= "\">";
    592             $interactionForm .= "<div class='cpress-col cpress-pl-0'>" . __('Font', 'chordpress') . "
    593               <div class='cpress-btn-group' role='group'>
    594                 <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', -5);\">-</button>
    595                 <button id=\"btnFontSize-%cpressID%\"  type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 0);\">100%</button>
    596                 <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"changeFontSize('%cpressID%', 5);\">+</button>
    597               </div>
    598             </div>";
    599             if (!$this->hideTranspose) {
    600                 $interactionForm .= "<div class='cpress-col cpress-text-center' style='display: inline-block;'>";
    601                 if ($this->showNumericTranspose) {
    602                     $interactionForm .= "<span class=''>" . __('Transpose', 'chordpress') . "</span>
    603                       <div class='cpress-btn-group' role='group'>
    604                         <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'down');\">-</button>
    605                         <button id=\"btnTranspose-%cpressID%\" type='button' class='cpress-btn cpress-btn-outline-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'reset');\" value='0'>0</button>
    606                         <button type='button' class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"transposeChords('%cpressID%', 'btnTranspose-', 'up');\">+</button>
    607                       </div>";
    608                 } else {
    609                     //
    610                     // Let's see if a 'Key' directive was given. If so, we can add
    611                     // the transposed keys to the list.
    612                     //
    613                     if (strlen($this->arrDirectives['key']) && in_array($this->arrDirectives['key'], $this->arrKeys)) {
    614                         $i = 0;
    615                         foreach ($this->arrTransposeValues[$this->arrDirectives['key']] as $val) {
    616                             $tvalues[] = (string)$i . ' => ' . $val;
    617                             $i++;
    618                         }
    619                     } else {
    620                         $tvalues = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11');
    621                     }
    622                     $interactionForm .= __('Transpose', 'chordpress') . "
    623                     <select class=\"cpress-form-control cpress-form-control-sm cpress-w-50 cpress-py-0 cpress-px-2 float-right\" id=\"selTranspose-%cpressID%\" onchange=\"transposeChords('%cpressID%', 'selTranspose-');return false;\" title=\"" . __('Only works for international key names', 'chordpress') . ".\">
    624                         <option value=\"0\">" . $tvalues[0] . "</option>
    625                         <option value=\"1\">" . $tvalues[1] . "</option>
    626                         <option value=\"2\">" . $tvalues[2] . "</option>
    627                         <option value=\"3\">" . $tvalues[3] . "</option>
    628                         <option value=\"4\">" . $tvalues[4] . "</option>
    629                         <option value=\"5\">" . $tvalues[5] . "</option>
    630                         <option value=\"6\">" . $tvalues[6] . "</option>
    631                         <option value=\"7\">" . $tvalues[7] . "</option>
    632                         <option value=\"8\">" . $tvalues[8] . "</option>
    633                         <option value=\"9\">" . $tvalues[9] . "</option>
    634                         <option value=\"10\">" . $tvalues[10] . "</option>
    635                         <option value=\"11\">" . $tvalues[11] . "</option>
    636                     </select>";
    637                 }
    638                 $interactionForm .=  "</div>";
    639             }
    640             $interactionForm .= "<div class='cpress-col cpress-text-end cpress-pr-0'>";
    641             if (!$this->hidePrint) {
    642                 $interactionForm .=  "<button class='cpress-btn cpress-btn-secondary cpress-btn-sm' onclick=\"window.print();\">" . __('Print', 'chordpress') . "</button>\n";
    643             }
    644             $interactionForm .=  "</div>";
    645             $returnText .= $interactionForm . "</div>\n";
     1220        break;
     1221      case 2:
     1222        if ($this->displayHBNotation) {
     1223          $retVal = 'H';
     1224        } else {
     1225          $retVal = 'B';
    6461226        }
    647 
    648         $returnText .= "<div id=\"%cpressID%\" class=\"cpress\">\n";
    649 
    650         /**
    651          * Print header if directives exist
    652          */
    653         $randId = $this->random_string(true);
    654         if (strlen($this->arrDirectives['title']) && !$this->hideTitle) {
    655             $cpressID = str_replace(' ', '-', strtolower(trim($this->arrDirectives['title']))) . '-' . $randId;
    656             $returnText = str_replace('%cpressID%', $cpressID, $returnText);
    657             $returnText .= '<' . $this->titleLevel . '>' . $this->arrDirectives['title'] . '</' . $this->titleLevel . ">\n";
    658         } else {
    659             $cpressID = 'ccpress-id-' . $randId;
    660             $returnText = str_replace('%cpressID%', $cpressID, $returnText);
    661         }
    662 
    663         if (strlen($this->arrDirectives['subtitle']) && !$this->hideSubtitle) {
    664             $returnText .= '<' . $this->subtitleLevel . '>' . $this->arrDirectives['subtitle'] . '</' . $this->subtitleLevel . ">\n";
    665         }
    666 
    667         if (
    668             strlen($this->arrDirectives['album']) ||
    669             strlen($this->arrDirectives['artist']) ||
    670             strlen($this->arrDirectives['capo']) ||
    671             strlen($this->arrDirectives['composer']) ||
    672             strlen($this->arrDirectives['key']) ||
    673             strlen($this->arrDirectives['tempo']) ||
    674             strlen($this->arrDirectives['time']) ||
    675             strlen($this->arrDirectives['year'])
    676         ) {
    677             $returnText .= "<div class=\"cpress_meta\">\n";
    678             if (strlen($this->arrDirectives['composer']) && !$this->hideComposer) $returnText .= esc_html(__('Composer', 'chordpress')) . ': ' . $this->arrDirectives['composer'] . "<br>\n";
    679             if (strlen($this->arrDirectives['artist']) && !$this->hideArtist) $returnText .= esc_html(__('Artist', 'chordpress')) . ': ' . $this->arrDirectives['artist'] . "<br>\n";
    680             if (strlen($this->arrDirectives['year']) && !$this->hideYear) $returnText .= esc_html(__('Year', 'chordpress')) . ': ' . $this->arrDirectives['year'] . "<br>\n";
    681             if (strlen($this->arrDirectives['album']) && !$this->hideAlbum) $returnText .= esc_html(__('Album', 'chordpress')) . ': ' . $this->arrDirectives['album'] . "<br>\n";
    682 
    683             if (strlen($this->arrDirectives['key'])) {
    684                 $returnText .= esc_html(__('Key (original)', 'chordpress')) . ': ' . $this->arrDirectives['key'] . "<br>\n";
    685                 $returnText .= esc_html(__('Key (transposed)', 'chordpress')) . ': <span class="chord-hidable-%cpressID% key-%cpressID%-0">' . $this->arrDirectives['key'] . '</span>';
    686                 for ($t = 1; $t <= 11; $t++) {
    687                     $returnText .= '<span class="chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none">' . $this->arrTransposeValues[$this->arrDirectives['key']][$t] . '</span>';
    688                 }
    689                 $returnText .= "<br>\n";
    690             }
    691 
    692             if (strlen($this->arrDirectives['time'])) $returnText .= esc_html(__('Time', 'chordpress')) . ': ' . $this->arrDirectives['time'] . "<br>\n";
    693             if (strlen($this->arrDirectives['tempo'])) $returnText .= esc_html(__('Tempo', 'chordpress')) . ': ' . $this->arrDirectives['tempo'] . "<br>\n";
    694             if (strlen($this->arrDirectives['capo'])) $returnText .= esc_html(__('Capo', 'chordpress')) . ': ' . $this->arrDirectives['capo'] . "<br>\n";
    695             $returnText = preg_replace('/<br>$/', '', $returnText); // Remove last <br>
    696             $returnText .= "</div>\n";
    697         }
    698 
    699         /**
    700          * Go through each line and process it
    701          */
    702         $this->inMonospace = false;
    703 //        $this->C->dnd($text, false);
    704         foreach ($text as $line) {
    705             if ($this->inMonospace && strpos($line, "{end_of_monospace}") === false) {
    706                 $returnText .= $line;
    707             } else {
    708 //                $this->C->dnd("IN: " . $line, false);
    709                 $returnText .= $this->formatAndDisplayLine($line);
    710 //                $this->C->dnd("OUT: " . $returnText, false);
    711             }
    712         }
    713         $returnText = str_replace('%cpressID%', $cpressID, $returnText);
    714 //        $this->C->dnd($returnText, false);
    715 
    716         /**
    717          * End of ChordPress song
    718          */
    719         $returnText .= "</div>\n<!--end: ChordPress SongSheet-->\n";
    720 
    721         /**
    722          * Build chord sheet if option set to true.
    723          */
    724         if ($this->showChordSheet) {
    725             $chordSheetText = "\n<!--begin: ChordPress ChordSheet-->\n";
    726             $chordSheetText .= "<div class='cpress_chordsheet'>\n";
    727             $chordSheetText .= "<div><hr></div>\n";
    728             $chordSheetText .= "<p><i>" . esc_html(__('These known chords are used in this song', 'chordpress')) . ".</i></p>";
    729             $this->uniqueChords = array_unique($this->allChords);
    730             foreach ($this->uniqueChords as $uc) {
    731                 if ($postid = $this->find_guitar_chord_post($uc)) {
    732                     $this->load_guitar_chord($postid);
    733                     $chordSheetText .= $this->C->createSvgChord(true);
    734                 }
    735             }
    736             $chordSheetText .= "</div>\n<div style=\"clear:both; padding: 16px 0 16px 0;\"><hr></div>\n<!--end: ChordPress ChordSheet-->\n\n";
    737             if ($this->showChordSheetOnTop) {
    738                 $returnText = $chordSheetText . $returnText;
    739             } else {
    740                 $returnText = $returnText . $chordSheetText;
    741             }
    742         }
    743 
    744         // $this->C->dnd($returnText);
    745         return $returnText . "\n\n";
    746     }
    747 
    748     //--------------------------------------------------------------------------
    749 
    750     /**
    751      * Process a single of the ChordPro text and return the formatted HTML.
    752      *
    753      * @param string $line - Single line from inside shortcode wrapper.
    754      * @return string - Formatted HTML.
    755      * @since 1.0.0
    756      */
    757     public function formatAndDisplayLine($line)
    758     {
    759         $returnText = "";
    760 
    761         /**
    762          * Array of chords
    763          */
    764         $arrChords = array();
    765 
    766         /**
    767          * Array of corresponding lyrics starting at a chord and ending prior
    768          * to the next chord or the end-of-line.
    769          */
    770         $arrLyrics = array();
    771 
    772         /**
    773          * Now check what this line is all about
    774          */
    775         if (substr_count($line, "[") == 0) {
    776             /**
    777              * No chords on this line
    778              */
    779             if (isset($line[0]) && ($line[0] == '#' || $line == '<br />')) {
    780                 /**
    781                  * Line starts with "#": It's a comment line => return empty string
    782                  */
    783                 return "";
    784             } else if ((isset($line[0]) && $line[0] == '{') || (isset($line[0]) && strpos($line, '{'))) {
    785                 /**
    786                  * Line starts with "{" or has one in it: It's a directive
    787                  * Some of them need consideration for the output
    788                  */
    789                 $directive = strstr($line, '{'); // Remove all before the {
    790                 $arrDirective = explode(":", $directive);
    791                 $directiveName = strtolower(str_replace('{', '', trim($arrDirective[0])));
    792                 if (isset($arrDirective[1])) $directiveValue = substr(trim($arrDirective[1]), 0, strpos(trim($arrDirective[1]), '}'));
    793 
    794                 /**
    795                  * In case the directive had no colon and value, $directiveName will
    796                  * still contain the trailing }. So let's remove that.
    797                  */
    798                 if (substr_count($directiveName, "}")) $directiveName = str_replace("}", "", $directiveName);
    799 
    800                 if (strpos($directiveName, 'start_of_verse') !== false) {
    801                     return "<div class=\"cpress_verse\">\n<div class=\"cpress_line\">\n";
    802                 } elseif (strpos($directiveName, 'end_of_verse') !== false) {
    803                     return "</div></div>\n";
    804                 } elseif (strpos($directiveName, 'start_of_chorus') !== false) {
    805                     return "<div class=\"cpress_chorus\">\n<div class=\"cpress_line\">\n";
    806                 } elseif (strpos($directiveName, 'end_of_chorus') !== false) {
    807                     return "</div></div>\n";
    808                 } elseif (strpos($directiveName, 'start_of_monospace') !== false) {
    809                     $this->inMonospace = true;
    810                     return "<pre>\n";
    811                 } elseif (strpos($directiveName, 'end_of_monospace') !== false) {
    812                     $this->inMonospace = false;
    813                     return "</pre>\n";
    814                 } elseif (
    815                     strpos($directiveName, 'title') !== false ||
    816                     strpos($directiveName, 'subtitle') !== false ||
    817                     strpos($directiveName, 'album') !== false ||
    818                     strpos($directiveName, 'artist') !== false ||
    819                     strpos($directiveName, 'capo') !== false ||
    820                     strpos($directiveName, 'composer') !== false ||
    821                     strpos($directiveName, 'key') !== false ||
    822                     strpos($directiveName, 'tempo') !== false ||
    823                     strpos($directiveName, 'time') !== false ||
    824                     strpos($directiveName, 'year') !== false ||
    825                     strpos($directiveName, 'artist') !== false
    826                 ) {
    827                     //
    828                     // We have already processed these directives. Just return empty for this line.
    829                     //
    830                     return "";
    831                 } elseif (strpos($directiveName, 'comment') !== false && !$this->hideComments) {
    832                     $arrLyrics[] = '<span class="cpress_comment">' . $directiveValue . '</span>';
    833                 }
    834             } else {
    835                 /**
    836                  * Just lyrics without chords => print it
    837                  */
    838                 $arrLyrics[] = $line;
    839             }
    840         } elseif (substr_count($line, "[") != substr_count($line, "]")) {
    841             /**
    842              * Square bracket missing in this line
    843              */
    844             $arrLyrics[] = '<span style="color:#FF0000;"><i>' . esc_html(__('Missing square bracket in line', 'chordpress')) . ':</i></span> <code>' . $line . "</code>";
    845         } else {
    846             /**
    847              * Chords found. Split the line into segments beginning with '['
    848              */
    849             $arrBracketSegments = explode("[", $line);
    850             foreach ($arrBracketSegments as $segment) {
    851                 if (strlen($segment)) {
    852                     $pad = ($segment[strlen($segment) - 1] == ' ') ? '&nbsp;' : '';
    853                     /**
    854                      * Does the first segment start before the 1st '['?
    855                      */
    856                     if (substr_count($segment, "]") == 0) {
    857                         $arrChords[] = " ";
    858                         $arrLyrics[] = $segment . $pad;
    859                     } else {
    860                         /**
    861                          * Split this segment into chord an lyrics
    862                          */
    863                         $arrChordLyric = explode("]", $segment);
    864                         $arrChords[] = trim($arrChordLyric[0]);
    865                         $arrLyrics[] = $arrChordLyric[1] . $pad;
    866                     }
    867                 }
    868             }
    869         }
    870 
    871         /**
    872          * Start of line wrapper (lyrics and chords)
    873          */
    874         $returnText .= "<div class=\"cpress_line\">\n";
    875 
    876         /**
    877          * Align chords and lyrics together by wrapping each in a floating inline div
    878          */
    879         if (!$this->hideChords) {
    880 
    881             for ($i = 0; $i < count($arrChords); $i++) {
    882 
    883                 if (strlen(trim($arrChords[$i])) > 0 || strlen(trim($arrLyrics[$i])) > 0) {
    884 
    885                     $lyrics = trim($this->stripTags($arrLyrics[$i]));
    886 
    887                     /**
    888                      * Start of line-section (one chord and its lyrics)
    889                      */
    890                     $returnText .= "<div class=\"cpress_line_section\">\n";
    891 
    892                     if (strlen(trim($arrChords[$i])) > 0) {
    893 
    894                         $returnText .= "<div class=\"chord chord-hidable-%cpressID% key-%cpressID%-0\"><span class=\"chordshort\">";
    895 
    896                         /**
    897                          * Allow chords starting with a ~, |, / and . as chord placeholders. Just return the string.
    898                          * Att: ... will end up as &ellip; . Use blanks between each dot.
    899                          */
    900                         if (in_array($arrChords[$i][0], ['~', '|', '/', '.'])) {
    901                             $returnText .= $arrChords[$i];
    902                         } else {
    903                             $theChord = $this->formatChord($arrChords[$i]);
    904                             $this->allChords[] = $theChord;
    905                             $returnText .= $theChord;
    906                         }
    907 
    908                         $returnText .= "</span>&nbsp;</div>\n";
    909 
    910                         /**
    911                          * Prepare all other 11 transposed versions of the chord
    912                          * but hide them. They need to be on the page for interactive
    913                          * mode to show/hide them via Javascript.
    914                          * But do not mark empty chord divs as hidable. They need to stay.
    915                          */
    916                         $returnText .= "\n";
    917                         $tempTranspose = $this->getTranspose();
    918 
    919                         for ($t = 1; $t <= 11; $t++) {
    920                             $this->setTranspose($t);
    921                             /**
    922                              * Allow chords starting with a ~ as chord placeholders. Just return the string.
    923                              */
    924                             if (in_array($arrChords[$i][0], ['~', '|', '/', '.'])) {
    925                                 $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $arrChords[$i] . '</span>&nbsp;</div>';
    926                                 $returnText .= "\n";
    927                             } else {
    928                                 /**
    929                                  * This is a real chord.
    930                                  */
    931                                 $theChord = $this->formatChord($arrChords[$i]);
    932                                 $returnText .= '<div class="chord chord-hidable-%cpressID% key-%cpressID%-' . $t . '" style="display:none"><span class="chordshort">' . $theChord . '</span>&nbsp;</div>';
    933                             }
    934                         }
    935 
    936                         $this->setTranspose($tempTranspose);
    937 
    938                         /**
    939                          * Now add the lyrics for this section.
    940                          */
    941                         $returnText .= '<div class="lyric">';
    942 
    943                         if (strlen($lyrics) > 0) {
    944                             $endOf1stWord = strpos($lyrics, ' ');
    945                             $numSpaces = substr_count($lyrics, ' ');
    946                             if ($endOf1stWord > 0 && $numSpaces == 1) {
    947                                 $returnText .= substr($lyrics, 0, $endOf1stWord) . '&nbsp;';
    948                                 $lyrics = substr($lyrics, $endOf1stWord);
    949                                 $returnText .= "</div></div>\n<div class=\"cpress_line_section\">\n<div class=\"chord\">&nbsp;</div><div class=\"lyric\">";
    950                             }
    951                         }
    952                     } else {
    953                         $returnText .= '<div class="chord">&nbsp;</div>';
    954                         $returnText .= '<div class="lyric">';
    955                     }
    956 
    957                     if (strlen($lyrics) > 0) $returnText .= $lyrics;
    958                     $returnText .= "</div>\n"; // end of lyric
    959                     $returnText .= "</div>\n"; // end of line
    960 
    961                 }
    962             }
    963 
    964             /**
    965              * If there are more lyric parts than chord parts, add them here
    966              */
    967             for ($i = count($arrChords); $i < count($arrLyrics); $i++) {
    968                 $returnText .= $arrLyrics[$i];
    969             }
    970         } else {
    971 
    972             /**
    973              * Hide chords was selected, so only show the lyrics
    974              */
    975             $returnText .= '<div class="cpress_line_section"><div class="lyric">';
    976 
    977             for ($i = 0; $i < count($arrLyrics); $i++) {
    978                 $returnText .= $arrLyrics[$i];
    979             }
    980 
    981             $returnText .= "</div></div>";
    982         }
    983 
    984         /**
    985          * End of line wrapper
    986          */
    987         $returnText .= "</div>\n";
    988 
    989         /**
    990          * Add a clear:both div
    991          */
    992         $returnText .= "<div class='cpress_clear'></div>\n";
    993 
    994         return $returnText;
    995     }
    996 
    997     //--------------------------------------------------------------------------
    998 
    999     /**
    1000      * Remove all <> wrapped text from a string.
    1001      *
    1002      * @param string $string - String to process.
    1003      * @return string - Stripped text.
    1004      * @since 1.0.0
    1005      */
    1006     private function stripTags($string)
    1007     {
    1008         $retString = "";
    1009         $isVisible = true;
    1010         for ($i = 0; $i < strlen($string); $i++) {
    1011             if ($isVisible) {
    1012                 if ($string[$i] == '<')
    1013                     $isVisible = false;
    1014                 else
    1015                     $retString .= $string[$i];
    1016             } elseif ($string[$i] == '>') {
    1017                 $isVisible = true;
    1018             }
    1019         }
    1020         return $retString;
    1021     }
    1022 
    1023     //--------------------------------------------------------------------------
    1024 
    1025     /**
    1026      * Processes a note text and returns the formatted HTML.
    1027      *
    1028      * @param string $ch - Chord text, e.g. "A" or "B#" or "Db/F" or "IV".
    1029      * @return string - Uppercase note string.
    1030      * @since 1.0.0
    1031      */
    1032     public function formatChord($ch)
    1033     {
    1034         $useFlats = false;
    1035         if (strlen($ch) == 0) return '';
    1036 
    1037         /**
    1038          * Return other valid chord identifiers as is
    1039          */
    1040         $italianChords = array('Do', 'do', 'Re', 're', 'Mi', 'mi', 'Fa', 'fa', 'Sol', 'sol', 'La', 'la', 'Si', 'si');
    1041         $nashvilleChords = array('1', '2', '3', '4', '5', '6', '7');
    1042         $romanChords = array('I', 'I7', 'II', 'III', 'iii', 'IV', 'V', 'V7', 'VI', 'vi', 'VI7', 'vi7', 'VII');
    1043         if (in_array($ch, $italianChords) or in_array($ch, $nashvilleChords) or in_array($ch, $romanChords)) return $ch;
    1044 
    1045         /**
    1046          * The first letter should be the key note
    1047          */
    1048         $note = substr($ch, 0, 1);
    1049         $rem = substr($ch, 1);
    1050 
    1051         /**
    1052          * Convert note to a number
    1053          */
    1054         $noteVal = $this->noteToNumber($note);
    1055 
    1056         /**
    1057          * Check sharp/flat
    1058          */
    1059         if (strlen($rem) > 0) {
    1060             if (substr($rem, 0, 1) == '#') {
    1061                 $noteVal++;
    1062                 $rem = substr($rem, 1);
    1063             } elseif (strncasecmp($rem, "b", 1) == 0) {
    1064                 $useFlats = true;
    1065                 $noteVal--;
    1066                 $rem = substr($rem, 1);
    1067             }
    1068         }
    1069 
    1070         /**
    1071          * Add transpose
    1072          */
    1073         $noteVal += $this->transpose;
    1074         if ($noteVal > 11) $noteVal -= 12;
    1075         if ($noteVal < 0) $noteVal += 12;
    1076 
    1077         /**
    1078          * Build note to display from numeric note value
    1079          */
    1080         $xlatedNote = $this->numberToNote($noteVal, $useFlats);
    1081         // die($this->pretty_dump($xlatedNote));
    1082 
    1083         /**
    1084          * Return the chord display plus the bass note (if any)
    1085          */
    1086         return $xlatedNote . $this->formatRemainder($rem);
    1087     }
    1088 
    1089     //--------------------------------------------------------------------------
    1090 
    1091     /**
    1092      * Process the remainder of the given chord.
    1093      *
    1094      * @param string $remainder - Chord text starting at second char.
    1095      * @return string - Formatted remainder.
    1096      * @since 1.0.0
    1097      */
    1098     public function formatRemainder($remainder)
    1099     {
    1100         $indexOfSlash = strpos($remainder, '/');
    1101         if ($indexOfSlash === false) return $remainder;
    1102 
    1103         /**
    1104          * We have a slash, indicating that a bass note follows.
    1105          * Break the string into 2 parts at the slash.
    1106          * The slash will be lost, and will need to be added back later.
    1107          */
    1108         $chord = substr($remainder, 0, $indexOfSlash);
    1109         $bass = substr($remainder, $indexOfSlash + 1);
    1110 
    1111         $useFlats = false;
    1112 
    1113         if (strlen($bass) == 0) return $chord . "/?";
    1114 
    1115         /**
    1116          * The first letter should be the bass note
    1117          */
    1118         $note = substr($bass, 0, 1);
    1119         $xlatedNote = $note;
    1120         $rem = substr($bass, 1);
    1121 
    1122         /**
    1123          * Convert note to a number
    1124          */
    1125         $noteVal = $this->noteToNumber($note);
    1126 
    1127         /**
    1128          * Check sharp/flat
    1129          */
    1130         if (strlen($rem) > 0) {
    1131             if (substr($rem, 0, 1) == '#') {
    1132                 $noteVal++;
    1133                 $rem = substr($rem, 1);
    1134             } elseif (strncasecmp($rem, "b", 1) == 0) {
    1135                 $useFlats = true;
    1136                 $noteVal--;
    1137                 $rem = substr($rem, 1);
    1138             }
    1139         }
    1140 
    1141         /**
    1142          * Add transpose
    1143          */
    1144         $noteVal += $this->transpose;
    1145         if ($noteVal > 11) $noteVal -= 12;
    1146         if ($noteVal < 0) $noteVal += 12;
    1147 
    1148         /**
    1149          * Build note to display from numeric note value
    1150          */
    1151         $xlatedNote = $this->numberToNote($noteVal);
    1152 
    1153         return $chord . "/" . $xlatedNote . $rem;
    1154     }
    1155 
    1156     //--------------------------------------------------------------------------
    1157 
    1158     /**
    1159      * Convert note to number.
    1160      *
    1161      * @param string $n - Note to convert.
    1162      * @return integer
    1163      * @since 1.0.0
    1164      */
    1165     public function noteToNumber($n)
    1166     {
    1167         $regularNotation = array(
    1168             'A' => 0,
    1169             'B' => 2,
    1170             'C' => 3,
    1171             'D' => 5,
    1172             'E' => 7,
    1173             'F' => 8,
    1174             'G' => 10,
    1175         );
    1176 
    1177         $hbNotation = array(
    1178             'A' => 0,
    1179             'B' => 1,
    1180             'H' => 2,
    1181             'C' => 3,
    1182             'D' => 5,
    1183             'E' => 7,
    1184             'F' => 8,
    1185             'G' => 10,
    1186         );
    1187 
    1188         if (in_array(strtolower($this->hbNotation), array("yes", "1", "true"))) {
    1189             if (array_key_exists(strtoupper($n), $hbNotation)) {
    1190                 return $hbNotation[strtoupper($n)];
    1191             } else {
    1192                 return 0;
    1193             }
    1194         } else {
    1195             if (array_key_exists(strtoupper($n), $regularNotation)) {
    1196                 return $regularNotation[strtoupper($n)];
    1197             } else {
    1198                 return 0;
    1199             }
    1200         }
    1201     }
    1202 
    1203     //--------------------------------------------------------------------------
    1204 
    1205     /**
    1206      * Convert number to note.
    1207      *
    1208      * @param integer $n - Numeric note value to convert to note string.
    1209      * @param boolean $useFlats - Whether to use flat notes or not.
    1210      * @return string
    1211      * @since 1.0.0
    1212      */
    1213     public function numberToNote($n, $useFlats = false)
    1214     {
    1215         $retVal = '';
    1216 
    1217         switch ($n) {
    1218             case 0:
    1219                 $retVal = 'A';
    1220                 break;
    1221             case 1:
    1222                 if ($this->displayHBNotation) {
    1223                     $retVal = 'B';
    1224                 } else {
    1225                     if ($useFlats) $retVal = "Bb";
    1226                     else $retVal = "A#";
    1227                 }
    1228                 break;
    1229             case 2:
    1230                 if ($this->displayHBNotation) {
    1231                     $retVal = 'H';
    1232                 } else {
    1233                     $retVal = 'B';
    1234                 }
    1235                 break;
    1236             case 3:
    1237                 $retVal = 'C';
    1238                 break;
    1239             case 4:
    1240                 if ($useFlats) $retVal = "Db";
    1241                 else $retVal = "C#";
    1242                 break;
    1243             case 5:
    1244                 $retVal = 'D';
    1245                 break;
    1246             case 6:
    1247                 if ($useFlats) $retVal = "Eb";
    1248                 else $retVal = "D#";
    1249                 break;
    1250             case 7:
    1251                 $retVal = 'E';
    1252                 break;
    1253             case 8:
    1254                 $retVal = 'F';
    1255                 break;
    1256             case 9:
    1257                 if ($useFlats) $retVal = "Gb";
    1258                 else $retVal = "F#";
    1259                 break;
    1260             case 10:
    1261                 $retVal = 'G';
    1262                 break;
    1263             case 11:
    1264                 if ($useFlats) $retVal = "Ab";
    1265                 else $retVal = "G#";
    1266                 break;
    1267         }
    1268         return $retVal;
    1269     }
    1270 
    1271     //--------------------------------------------------------------------------
    1272 
    1273     /**
    1274      * Set class variable: displayHBNotation.
    1275      *
    1276      * @param boolean $g
    1277      * @since 1.0.0
    1278      */
    1279     public function setDisplayHBNotation($g)
    1280     {
    1281         $this->displayHBNotation = $g;
    1282     }
    1283 
    1284     //--------------------------------------------------------------------------
    1285 
    1286     /**
    1287      * Get class variable: displayHBNotation.
    1288      *
    1289      * @return boolean
    1290      * @since 1.0.0
    1291      */
    1292     public function getDisplayHBNotation()
    1293     {
    1294         return $this->displayHBNotation;
    1295     }
    1296 
    1297     //--------------------------------------------------------------------------
    1298 
    1299     /**
    1300      * Set class variable: float.
    1301      *
    1302      * @param string $f - left/right/none/inherit.
    1303      * @since 1.0.0
    1304      */
    1305     public function setFloat($f)
    1306     {
    1307         $this->float = $f;
    1308     }
    1309 
    1310     //--------------------------------------------------------------------------
    1311 
    1312     /**
    1313      * Get class variable: float.
    1314      *
    1315      * @return string
    1316      * @since 1.0.0
    1317      */
    1318     public function getFloat()
    1319     {
    1320         return $this->float;
    1321     }
    1322 
    1323     //--------------------------------------------------------------------------
    1324 
    1325     /**
    1326      * Set class variable: hbNotation.
    1327      *
    1328      * @param string $g - yes/no.
    1329      * @since 1.0.0
    1330      */
    1331     public function setHBNotation($g)
    1332     {
    1333         $this->hbNotation = $g;
    1334     }
    1335 
    1336     //--------------------------------------------------------------------------
    1337 
    1338     /**
    1339      * Get class variable: hideChords.
    1340      *
    1341      * @return string -yes/no.
    1342      * @since 3.5.0
    1343      */
    1344     public function getHideChords()
    1345     {
    1346         return $this->hideChords;
    1347     }
    1348 
    1349     //--------------------------------------------------------------------------
    1350 
    1351     /**
    1352      * Set class variable: hideChords.
    1353      *
    1354      * @param string $g - yes/no.
    1355      * @since 3.5.0
    1356      */
    1357     public function setHideChords($g)
    1358     {
    1359         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1360             $this->hideChords = true;
    1361         } else {
    1362             $this->hideChords = false;
    1363         }
    1364     }
    1365 
    1366     //--------------------------------------------------------------------------
    1367 
    1368     /**
    1369      * Get class variable: hideComments.
    1370      *
    1371      * @return string -yes/no.
    1372      * @since 3.5.0
    1373      */
    1374     public function getHideComments()
    1375     {
    1376         return $this->hideComments;
    1377     }
    1378 
    1379     //--------------------------------------------------------------------------
    1380 
    1381     /**
    1382      * Set class variable: hideComments.
    1383      *
    1384      * @param string $g - yes/no.
    1385      * @since 3.5.0
    1386      */
    1387     public function setHideComments($g)
    1388     {
    1389         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1390             $this->hideComments = 1;
    1391         } else {
    1392             $this->hideComments = 0;
    1393         }
    1394     }
    1395 
    1396     //--------------------------------------------------------------------------
    1397 
    1398     /**
    1399      * Get class variable: hideComposer.
    1400      *
    1401      * @return string -yes/no.
    1402      * @since 3.5.0
    1403      */
    1404     public function getHideComposer()
    1405     {
    1406         return $this->hideComposer;
    1407     }
    1408 
    1409     //--------------------------------------------------------------------------
    1410 
    1411     /**
    1412      * Set class variable: hideComposer.
    1413      *
    1414      * @param string $g - yes/no.
    1415      * @since 3.5.0
    1416      */
    1417     public function setHideComposer($g)
    1418     {
    1419         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1420             $this->hideComposer = 1;
    1421         } else {
    1422             $this->hideComposer = 0;
    1423         }
    1424     }
    1425 
    1426     //--------------------------------------------------------------------------
    1427 
    1428     /**
    1429      * Get class variable: hidePrint.
    1430      *
    1431      * @return string -yes/no.
    1432      * @since 3.5.0
    1433      */
    1434     public function getHidePrint()
    1435     {
    1436         return $this->hidePrint;
    1437     }
    1438 
    1439     //--------------------------------------------------------------------------
    1440 
    1441     /**
    1442      * Set class variable: hidePrint.
    1443      *
    1444      * @param string $g - yes/no.
    1445      * @since 3.5.0
    1446      */
    1447     public function setHidePrint($g)
    1448     {
    1449         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1450             $this->hidePrint = 1;
    1451         } else {
    1452             $this->hidePrint = 0;
    1453         }
    1454     }
    1455 
    1456     //--------------------------------------------------------------------------
    1457 
    1458     /**
    1459      * Get class variable: hideSubtitle.
    1460      *
    1461      * @return string -yes/no.
    1462      * @since 3.5.0
    1463      */
    1464     public function getHideSubtitle()
    1465     {
    1466         return $this->hideSubtitle;
    1467     }
    1468 
    1469     //--------------------------------------------------------------------------
    1470 
    1471     /**
    1472      * Set class variable: hideSubtitle.
    1473      *
    1474      * @param string $g - yes/no.
    1475      * @since 3.5.0
    1476      */
    1477     public function setHideSubtitle($g)
    1478     {
    1479         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1480             $this->hideSubtitle = 1;
    1481         } else {
    1482             $this->hideSubtitle = 0;
    1483         }
    1484     }
    1485 
    1486     //--------------------------------------------------------------------------
    1487 
    1488     /**
    1489      * Get class variable: hideTitle.
    1490      *
    1491      * @return string -yes/no.
    1492      * @since 3.5.0
    1493      */
    1494     public function getHideTitle()
    1495     {
    1496         return $this->hideTitle;
    1497     }
    1498 
    1499     //--------------------------------------------------------------------------
    1500 
    1501     /**
    1502      * Set class variable: hideTitle.
    1503      *
    1504      * @param string $g - yes/no.
    1505      * @since 3.5.0
    1506      */
    1507     public function setHideTitle($g)
    1508     {
    1509         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1510             $this->hideTitle = 1;
    1511         } else {
    1512             $this->hideTitle = 0;
    1513         }
    1514     }
    1515 
    1516     //--------------------------------------------------------------------------
    1517 
    1518     /**
    1519      * Get class variable: hideTranspose.
    1520      *
    1521      * @return string -yes/no.
    1522      * @since 3.5.0
    1523      */
    1524     public function getHideTranspose()
    1525     {
    1526         return $this->hideTranspose;
    1527     }
    1528 
    1529     //--------------------------------------------------------------------------
    1530 
    1531     /**
    1532      * Set class variable: hideTranspose.
    1533      *
    1534      * @param string $g - yes/no.
    1535      * @since 3.5.0
    1536      */
    1537     public function setHideTranspose($g)
    1538     {
    1539         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1540             $this->hideTranspose = 1;
    1541         } else {
    1542             $this->hideTranspose = 0;
    1543         }
    1544     }
    1545 
    1546     //--------------------------------------------------------------------------
    1547 
    1548     /**
    1549      * Get class variable: showNumericTranspose.
    1550      *
    1551      * @return string -yes/no.
    1552      * @since 3.6.0
    1553      */
    1554     public function getNumericTranspose()
    1555     {
    1556         return $this->showNumericTranspose;
    1557     }
    1558 
    1559     //--------------------------------------------------------------------------
    1560 
    1561     /**
    1562      * Set class variable: showNumericTranspose.
    1563      *
    1564      * @param string $g - yes/no.
    1565      * @since 3.6.0
    1566      */
    1567     public function setNumericTranspose($g)
    1568     {
    1569         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1570             $this->showNumericTranspose = 1;
    1571         } else {
    1572             $this->showNumericTranspose = 0;
    1573         }
    1574     }
    1575 
    1576     //--------------------------------------------------------------------------
    1577 
    1578     /**
    1579      * Get class variable: fixedInteraction.
    1580      *
    1581      * @return string -yes/no.
    1582      * @since 3.6.0
    1583      */
    1584     public function getFixedInteraction()
    1585     {
    1586         return $this->fixedInteraction;
    1587     }
    1588 
    1589     //--------------------------------------------------------------------------
    1590 
    1591     /**
    1592      * Set class variable: fixedInteraction.
    1593      *
    1594      * @param string $g - yes/no.
    1595      * @since 3.6.0
    1596      */
    1597     public function setFixedInteraction($g)
    1598     {
    1599         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1600             $this->fixedInteraction = 1;
    1601         } else {
    1602             $this->fixedInteraction = 0;
    1603         }
    1604     }
    1605 
    1606     //--------------------------------------------------------------------------
    1607 
    1608     /**
    1609      * Get class variable: hideYear.
    1610      *
    1611      * @return string -yes/no.
    1612      * @since 3.5.0
    1613      */
    1614     public function getHideYear()
    1615     {
    1616         return $this->hideYear;
    1617     }
    1618 
    1619     //--------------------------------------------------------------------------
    1620 
    1621     /**
    1622      * Set class variable: hideYear.
    1623      *
    1624      * @param string $g - yes/no.
    1625      * @since 3.5.0
    1626      */
    1627     public function setHideYear($g)
    1628     {
    1629         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1630             $this->hideYear = 1;
    1631         } else {
    1632             $this->hideYear = 0;
    1633         }
    1634     }
    1635 
    1636     //--------------------------------------------------------------------------
    1637 
    1638     /**
    1639      * Get class variable: hbNotation.
    1640      *
    1641      * @return string -yes/no.
    1642      * @since 1.0.0
    1643      */
    1644     public function getHBNotation()
    1645     {
    1646         return $this->hbNotation;
    1647     }
    1648 
    1649     //--------------------------------------------------------------------------
    1650 
    1651     /**
    1652      * Set class variable: interactive.
    1653      *
    1654      * @param string $g - yes/no.
    1655      * @since 1.0.0
    1656      */
    1657     public function setInteractive($i)
    1658     {
    1659         $this->interactive = $i;
    1660     }
    1661 
    1662     //--------------------------------------------------------------------------
    1663 
    1664     /**
    1665      * Get class variable: interactive.
    1666      *
    1667      * @return string - yes/no.
    1668      * @since 1.0.0
    1669      */
    1670     public function getInteractive()
    1671     {
    1672         return $this->interactive;
    1673     }
    1674 
    1675     //--------------------------------------------------------------------------
    1676 
    1677     /**
    1678      * Get class variable: showChordSheet.
    1679      *
    1680      * @return string -yes/no.
    1681      * @since 3.5.0
    1682      */
    1683     public function getShowChordSheet()
    1684     {
    1685         return $this->showChordSheet;
    1686     }
    1687 
    1688     //--------------------------------------------------------------------------
    1689 
    1690     /**
    1691      * Set class variable: hideYear.
    1692      *
    1693      * @param string $g - yes/no.
    1694      * @since 3.5.0
    1695      */
    1696     public function setShowChordSheet($g)
    1697     {
    1698         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1699             $this->showChordSheet = 1;
    1700         } else {
    1701             $this->showChordSheet = 0;
    1702         }
    1703     }
    1704 
    1705     //--------------------------------------------------------------------------
    1706 
    1707     /**
    1708      * Get class variable: showChordSheetOnTop.
    1709      *
    1710      * @return string -yes/no.
    1711      * @since 3.5.0
    1712      */
    1713     public function getShowChordSheetOnTop()
    1714     {
    1715         return $this->showChordSheetOnTop;
    1716     }
    1717 
    1718     //--------------------------------------------------------------------------
    1719 
    1720     /**
    1721      * Set class variable: hideYear.
    1722      *
    1723      * @param string $g - yes/no.
    1724      * @since 3.5.0
    1725      */
    1726     public function setShowChordSheetOnTop($g)
    1727     {
    1728         if (in_array(strtolower($g), array("yes", "1", "true"))) {
    1729             $this->showChordSheetOnTop = 1;
    1730         } else {
    1731             $this->showChordSheetOnTop = 0;
    1732         }
    1733     }
    1734 
    1735     //--------------------------------------------------------------------------
    1736 
    1737     /**
    1738      * Sets class variable: transpose.
    1739      *
    1740      * @param integer $t - Positive or negative number of steps for transponation.
    1741      * @since 1.0.0
    1742      */
    1743     public function setTranspose($t)
    1744     {
    1745         $this->transpose = $t;
    1746     }
    1747 
    1748     //--------------------------------------------------------------------------
    1749 
    1750     /**
    1751      * Get class variable: transpose.
    1752      *
    1753      * @return integer
    1754      * @since 1.0.0
    1755      */
    1756     public function getTranspose()
    1757     {
    1758         return $this->transpose;
    1759     }
    1760 
    1761     //--------------------------------------------------------------------------
    1762 
    1763     /**
    1764      * Find a guitar chord type post by shortname.
    1765      *
    1766      * @param string $shortname - Shortname of the guitar post to look for.
    1767      * @return integer - Post ID or NULL
    1768      */
    1769     private function find_guitar_chord_post($shortname)
    1770     {
    1771         $query_args = array(
    1772             'posts_per_page' => 1,
    1773             'post_type' => 'guitar_chord',
    1774             'meta_key' => 'guitar_chord_name',
    1775             'meta_value' => $shortname
    1776         );
    1777         $query_result = new WP_Query($query_args);
    1778 
    1779         if (array_key_exists(0, $query_result->posts)) {
    1780             return $query_result->posts[0]->ID;
    1781         } else {
    1782             return 0;
    1783         }
    1784     }
    1785 
    1786     //--------------------------------------------------------------------------
    1787 
    1788     /**
    1789      * Load a guitar chord based on post ID.
    1790      *
    1791      * @param integer $postid - Guitar chord post ID.
    1792      * @return void
    1793      */
    1794     private function load_guitar_chord($postid)
    1795     {
    1796         $my_chord = array();
    1797         $post = get_post($postid);
    1798 
    1799         /**
    1800          * Retrieve meta data from chord post
    1801          */
    1802         $guitar_chord_name = get_post_meta($postid, 'guitar_chord_name', true);
    1803         if (get_post_meta($postid, 'guitar_chord_barres', true)) {
    1804             $guitar_chord_barres = get_post_meta($postid, 'guitar_chord_barres', true);
    1805         } else {
    1806             $guitar_chord_barres = "";
    1807         }
    1808         $guitar_chord_fingers = get_post_meta($postid, 'guitar_chord_fingers', true);
    1809         $guitar_chord_frets = get_post_meta($postid, 'guitar_chord_frets', true);
    1810         $guitar_chord_strings = get_post_meta($postid, 'guitar_chord_strings', true);
    1811         $guitar_chord_position = get_post_meta($postid, 'guitar_chord_position', true);
    1812         $guitar_chord_tuning = get_post_meta($postid, 'guitar_chord_tuning', true);
    1813 
    1814         /**
    1815          * Set chord properties
    1816          */
    1817         $this->C->setProperty('title', $guitar_chord_name);
    1818         $this->C->setBarres($guitar_chord_barres);
    1819         $this->C->setProperty('fingers', $this->C->replace_brackets($guitar_chord_fingers));
    1820         $this->C->setProperty('frets', $guitar_chord_frets);
    1821         $this->C->setProperty('position', $guitar_chord_position);
    1822         $this->C->setProperty('strings', $guitar_chord_strings);
    1823         $this->C->setTuning($guitar_chord_tuning);
    1824     }
    1825 
    1826     //--------------------------------------------------------------------------
    1827     /**
    1828      * Create a modal guitar chord dialog.
    1829      *
    1830      * @param integer $postid - ID of the chord post
    1831      * @param string $chord - Vexchord HTML
    1832      * @return string - Modal chord dialog HTML
    1833      */
     1227        break;
     1228      case 3:
     1229        $retVal = 'C';
     1230        break;
     1231      case 4:
     1232        if ($useFlats) $retVal = "Db";
     1233        else $retVal = "C#";
     1234        break;
     1235      case 5:
     1236        $retVal = 'D';
     1237        break;
     1238      case 6:
     1239        if ($useFlats) $retVal = "Eb";
     1240        else $retVal = "D#";
     1241        break;
     1242      case 7:
     1243        $retVal = 'E';
     1244        break;
     1245      case 8:
     1246        $retVal = 'F';
     1247        break;
     1248      case 9:
     1249        if ($useFlats) $retVal = "Gb";
     1250        else $retVal = "F#";
     1251        break;
     1252      case 10:
     1253        $retVal = 'G';
     1254        break;
     1255      case 11:
     1256        if ($useFlats) $retVal = "Ab";
     1257        else $retVal = "G#";
     1258        break;
     1259    }
     1260    return $retVal;
     1261  }
     1262
     1263  //---------------------------------------------------------------------------
     1264  /**
     1265   * Set class variable: displayHBNotation.
     1266   *
     1267   * @param boolean $g
     1268   * @since 1.0.0
     1269   */
     1270  public function setDisplayHBNotation($g) {
     1271    $this->displayHBNotation = $g;
     1272  }
     1273
     1274  //---------------------------------------------------------------------------
     1275  /**
     1276   * Get class variable: displayHBNotation.
     1277   *
     1278   * @return boolean
     1279   * @since 1.0.0
     1280   */
     1281  public function getDisplayHBNotation() {
     1282    return $this->displayHBNotation;
     1283  }
     1284
     1285  //---------------------------------------------------------------------------
     1286  /**
     1287   * Set class variable: float.
     1288   *
     1289   * @param string $f - left/right/none/inherit.
     1290   * @since 1.0.0
     1291   */
     1292  public function setFloat($f) {
     1293    $this->float = $f;
     1294  }
     1295
     1296  //---------------------------------------------------------------------------
     1297  /**
     1298   * Get class variable: float.
     1299   *
     1300   * @return string
     1301   * @since 1.0.0
     1302   */
     1303  public function getFloat() {
     1304    return $this->float;
     1305  }
     1306
     1307  //---------------------------------------------------------------------------
     1308  /**
     1309   * Set class variable: hbNotation.
     1310   *
     1311   * @param string $g - yes/no.
     1312   * @since 1.0.0
     1313   */
     1314  public function setHBNotation($g) {
     1315    $this->hbNotation = $g;
     1316  }
     1317
     1318  //---------------------------------------------------------------------------
     1319  /**
     1320   * Get class variable: hideChords.
     1321   *
     1322   * @return string -yes/no.
     1323   * @since 3.5.0
     1324   */
     1325  public function getHideChords() {
     1326    return $this->hideChords;
     1327  }
     1328
     1329  //---------------------------------------------------------------------------
     1330  /**
     1331   * Set class variable: hideChords.
     1332   *
     1333   * @param string $g - yes/no.
     1334   * @since 3.5.0
     1335   */
     1336  public function setHideChords($g) {
     1337    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1338      $this->hideChords = true;
     1339    } else {
     1340      $this->hideChords = false;
     1341    }
     1342  }
     1343
     1344  //---------------------------------------------------------------------------
     1345  /**
     1346   * Get class variable: hideComments.
     1347   *
     1348   * @return string -yes/no.
     1349   * @since 3.5.0
     1350   */
     1351  public function getHideComments() {
     1352    return $this->hideComments;
     1353  }
     1354
     1355  //---------------------------------------------------------------------------
     1356  /**
     1357   * Set class variable: hideComments.
     1358   *
     1359   * @param string $g - yes/no.
     1360   * @since 3.5.0
     1361   */
     1362  public function setHideComments($g) {
     1363    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1364      $this->hideComments = 1;
     1365    } else {
     1366      $this->hideComments = 0;
     1367    }
     1368  }
     1369
     1370  //---------------------------------------------------------------------------
     1371  /**
     1372   * Get class variable: hideComposer.
     1373   *
     1374   * @return string -yes/no.
     1375   * @since 3.5.0
     1376   */
     1377  public function getHideComposer() {
     1378    return $this->hideComposer;
     1379  }
     1380
     1381  //---------------------------------------------------------------------------
     1382  /**
     1383   * Set class variable: hideComposer.
     1384   *
     1385   * @param string $g - yes/no.
     1386   * @since 3.5.0
     1387   */
     1388  public function setHideComposer($g) {
     1389    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1390      $this->hideComposer = 1;
     1391    } else {
     1392      $this->hideComposer = 0;
     1393    }
     1394  }
     1395
     1396  //---------------------------------------------------------------------------
     1397  /**
     1398   * Get class variable: hidePrint.
     1399   *
     1400   * @return string -yes/no.
     1401   * @since 3.5.0
     1402   */
     1403  public function getHidePrint() {
     1404    return $this->hidePrint;
     1405  }
     1406
     1407  //---------------------------------------------------------------------------
     1408  /**
     1409   * Set class variable: hidePrint.
     1410   *
     1411   * @param string $g - yes/no.
     1412   * @since 3.5.0
     1413   */
     1414  public function setHidePrint($g) {
     1415    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1416      $this->hidePrint = 1;
     1417    } else {
     1418      $this->hidePrint = 0;
     1419    }
     1420  }
     1421
     1422  //---------------------------------------------------------------------------
     1423  /**
     1424   * Get class variable: hideSubtitle.
     1425   *
     1426   * @return string -yes/no.
     1427   * @since 3.5.0
     1428   */
     1429  public function getHideSubtitle() {
     1430    return $this->hideSubtitle;
     1431  }
     1432
     1433  //---------------------------------------------------------------------------
     1434  /**
     1435   * Set class variable: hideSubtitle.
     1436   *
     1437   * @param string $g - yes/no.
     1438   * @since 3.5.0
     1439   */
     1440  public function setHideSubtitle($g) {
     1441    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1442      $this->hideSubtitle = 1;
     1443    } else {
     1444      $this->hideSubtitle = 0;
     1445    }
     1446  }
     1447
     1448  //---------------------------------------------------------------------------
     1449  /**
     1450   * Get class variable: hideTitle.
     1451   *
     1452   * @return string -yes/no.
     1453   * @since 3.5.0
     1454   */
     1455  public function getHideTitle() {
     1456    return $this->hideTitle;
     1457  }
     1458
     1459  //---------------------------------------------------------------------------
     1460  /**
     1461   * Set class variable: hideTitle.
     1462   *
     1463   * @param string $g - yes/no.
     1464   * @since 3.5.0
     1465   */
     1466  public function setHideTitle($g) {
     1467    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1468      $this->hideTitle = 1;
     1469    } else {
     1470      $this->hideTitle = 0;
     1471    }
     1472  }
     1473
     1474  //---------------------------------------------------------------------------
     1475  /**
     1476   * Get class variable: hideTranspose.
     1477   *
     1478   * @return string -yes/no.
     1479   * @since 3.5.0
     1480   */
     1481  public function getHideTranspose() {
     1482    return $this->hideTranspose;
     1483  }
     1484
     1485  //---------------------------------------------------------------------------
     1486  /**
     1487   * Set class variable: hideTranspose.
     1488   *
     1489   * @param string $g - yes/no.
     1490   * @since 3.5.0
     1491   */
     1492  public function setHideTranspose($g) {
     1493    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1494      $this->hideTranspose = 1;
     1495    } else {
     1496      $this->hideTranspose = 0;
     1497    }
     1498  }
     1499
     1500  //---------------------------------------------------------------------------
     1501  /**
     1502   * Get class variable: showNumericTranspose.
     1503   *
     1504   * @return string -yes/no.
     1505   * @since 3.6.0
     1506   */
     1507  public function getNumericTranspose() {
     1508    return $this->showNumericTranspose;
     1509  }
     1510
     1511  //---------------------------------------------------------------------------
     1512  /**
     1513   * Set class variable: showNumericTranspose.
     1514   *
     1515   * @param string $g - yes/no.
     1516   * @since 3.6.0
     1517   */
     1518  public function setNumericTranspose($g) {
     1519    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1520      $this->showNumericTranspose = 1;
     1521    } else {
     1522      $this->showNumericTranspose = 0;
     1523    }
     1524  }
     1525
     1526  //---------------------------------------------------------------------------
     1527  /**
     1528   * Get class variable: fixedInteraction.
     1529   *
     1530   * @return string -yes/no.
     1531   * @since 3.6.0
     1532   */
     1533  public function getFixedInteraction() {
     1534    return $this->fixedInteraction;
     1535  }
     1536
     1537  //---------------------------------------------------------------------------
     1538  /**
     1539   * Set class variable: fixedInteraction.
     1540   *
     1541   * @param string $g - yes/no.
     1542   * @since 3.6.0
     1543   */
     1544  public function setFixedInteraction($g) {
     1545    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1546      $this->fixedInteraction = 1;
     1547    } else {
     1548      $this->fixedInteraction = 0;
     1549    }
     1550  }
     1551
     1552  //---------------------------------------------------------------------------
     1553  /**
     1554   * Get class variable: hideYear.
     1555   *
     1556   * @return string -yes/no.
     1557   * @since 3.5.0
     1558   */
     1559  public function getHideYear() {
     1560    return $this->hideYear;
     1561  }
     1562
     1563  //---------------------------------------------------------------------------
     1564  /**
     1565   * Set class variable: hideYear.
     1566   *
     1567   * @param string $g - yes/no.
     1568   * @since 3.5.0
     1569   */
     1570  public function setHideYear($g) {
     1571    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1572      $this->hideYear = 1;
     1573    } else {
     1574      $this->hideYear = 0;
     1575    }
     1576  }
     1577
     1578  //---------------------------------------------------------------------------
     1579  /**
     1580   * Get class variable: hbNotation.
     1581   *
     1582   * @return string -yes/no.
     1583   * @since 1.0.0
     1584   */
     1585  public function getHBNotation() {
     1586    return $this->hbNotation;
     1587  }
     1588
     1589  //---------------------------------------------------------------------------
     1590  /**
     1591   * Set class variable: interactive.
     1592   *
     1593   * @param string $g - yes/no.
     1594   * @since 1.0.0
     1595   */
     1596  public function setInteractive($i) {
     1597    $this->interactive = $i;
     1598  }
     1599
     1600  //---------------------------------------------------------------------------
     1601  /**
     1602   * Get class variable: interactive.
     1603   *
     1604   * @return string - yes/no.
     1605   * @since 1.0.0
     1606   */
     1607  public function getInteractive() {
     1608    return $this->interactive;
     1609  }
     1610
     1611  //---------------------------------------------------------------------------
     1612  /**
     1613   * Get class variable: showChordSheet.
     1614   *
     1615   * @return string -yes/no.
     1616   * @since 3.5.0
     1617   */
     1618  public function getShowChordSheet() {
     1619    return $this->showChordSheet;
     1620  }
     1621
     1622  //---------------------------------------------------------------------------
     1623  /**
     1624   * Set class variable: hideYear.
     1625   *
     1626   * @param string $g - yes/no.
     1627   * @since 3.5.0
     1628   */
     1629  public function setShowChordSheet($g) {
     1630    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1631      $this->showChordSheet = 1;
     1632    } else {
     1633      $this->showChordSheet = 0;
     1634    }
     1635  }
     1636
     1637  //---------------------------------------------------------------------------
     1638  /**
     1639   * Get class variable: showChordSheetOnTop.
     1640   *
     1641   * @return string -yes/no.
     1642   * @since 3.5.0
     1643   */
     1644  public function getShowChordSheetOnTop() {
     1645    return $this->showChordSheetOnTop;
     1646  }
     1647
     1648  //---------------------------------------------------------------------------
     1649  /**
     1650   * Set class variable: hideYear.
     1651   *
     1652   * @param string $g - yes/no.
     1653   * @since 3.5.0
     1654   */
     1655  public function setShowChordSheetOnTop($g) {
     1656    if (in_array(strtolower($g), array( "yes", "1", "true" ))) {
     1657      $this->showChordSheetOnTop = 1;
     1658    } else {
     1659      $this->showChordSheetOnTop = 0;
     1660    }
     1661  }
     1662
     1663  //---------------------------------------------------------------------------
     1664  /**
     1665   * Sets class variable: transpose.
     1666   *
     1667   * @param integer $t - Positive or negative number of steps for transponation.
     1668   * @since 1.0.0
     1669   */
     1670  public function setTranspose($t) {
     1671    $this->transpose = $t;
     1672  }
     1673
     1674  //---------------------------------------------------------------------------
     1675  /**
     1676   * Get class variable: transpose.
     1677   *
     1678   * @return integer
     1679   * @since 1.0.0
     1680   */
     1681  public function getTranspose() {
     1682    return $this->transpose;
     1683  }
     1684
     1685  //---------------------------------------------------------------------------
     1686  /**
     1687   * Find a guitar chord type post by shortname.
     1688   *
     1689   * @param string $shortname - Shortname of the guitar post to look for.
     1690   * @return integer - Post ID or NULL
     1691   */
     1692  private function find_guitar_chord_post($shortname) {
     1693    $query_args = array(
     1694      'posts_per_page' => 1,
     1695      'post_type' => 'guitar_chord',
     1696      'meta_key' => 'guitar_chord_name',
     1697      'meta_value' => $shortname
     1698    );
     1699    $query_result = new WP_Query($query_args);
     1700
     1701    if (array_key_exists(0, $query_result->posts)) {
     1702      return $query_result->posts[0]->ID;
     1703    } else {
     1704      return 0;
     1705    }
     1706  }
     1707
     1708  //---------------------------------------------------------------------------
     1709  /**
     1710   * Load a guitar chord based on post ID.
     1711   *
     1712   * @param integer $postid - Guitar chord post ID.
     1713   * @return void
     1714   */
     1715  private function load_guitar_chord($postid) {
     1716    $my_chord = array();
     1717    $post = get_post($postid);
     1718
     1719    /**
     1720     * Retrieve meta data from chord post
     1721     */
     1722    $guitar_chord_name = get_post_meta($postid, 'guitar_chord_name', true);
     1723    if (get_post_meta($postid, 'guitar_chord_barres', true)) {
     1724      $guitar_chord_barres = get_post_meta($postid, 'guitar_chord_barres', true);
     1725    } else {
     1726      $guitar_chord_barres = "";
     1727    }
     1728    $guitar_chord_fingers = get_post_meta($postid, 'guitar_chord_fingers', true);
     1729    $guitar_chord_frets = get_post_meta($postid, 'guitar_chord_frets', true);
     1730    $guitar_chord_strings = get_post_meta($postid, 'guitar_chord_strings', true);
     1731    $guitar_chord_position = get_post_meta($postid, 'guitar_chord_position', true);
     1732    $guitar_chord_tuning = get_post_meta($postid, 'guitar_chord_tuning', true);
     1733
     1734    /**
     1735     * Set chord properties
     1736     */
     1737    $this->C->setProperty('title', $guitar_chord_name);
     1738    $this->C->setBarres($guitar_chord_barres);
     1739    $this->C->setProperty('fingers', $this->C->replace_brackets($guitar_chord_fingers));
     1740    $this->C->setProperty('frets', $guitar_chord_frets);
     1741    $this->C->setProperty('position', $guitar_chord_position);
     1742    $this->C->setProperty('strings', $guitar_chord_strings);
     1743    $this->C->setTuning($guitar_chord_tuning);
     1744  }
     1745
     1746  //---------------------------------------------------------------------------
     1747  /**
     1748   * Create a modal guitar chord dialog.
     1749   *
     1750   * @param integer $postid - ID of the chord post
     1751   * @param string $chord - Vexchord HTML
     1752   * @return string - Modal chord dialog HTML
     1753   */
    18341754//    private function create_modal_chord($postid, $chord)
    18351755//    {
     
    18641784//    }
    18651785
    1866     //--------------------------------------------------------------------------
    1867     /**
    1868      * Generate random string.
    1869      *
    1870      * @param boolean $alphaonly - Whether to only use alpha charaters
    1871      * @param integer $length - Length of random string to generate
    1872      * @return false|string
    1873      */
    1874     private function random_string($alphaonly = false, $length = 15)
    1875     {
    1876         if ($alphaonly) {
    1877             return substr(str_shuffle(str_repeat($x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
    1878         } else {
    1879             return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
    1880         }
    1881     }
    1882 
    1883     // ---------------------------------------------------------------------------
    1884 
    1885     /**
    1886      * Dump and Die.
    1887      *
    1888      * @param array $a Array to print out pretty
    1889      * @param bool $die Flag to die after dump or not
    1890      * @return string
    1891      * @since 3.2.0
    1892      */
    1893     private function dnd($a, $die = true)
    1894     {
    1895         $dump = highlight_string("<?php\n\$data =\n" . var_export($a, true) . ";\n?>");
    1896         if ($die) die($dump);
    1897         else return $dump;
    1898     }
     1786  //---------------------------------------------------------------------------
     1787  /**
     1788   * Generate random string.
     1789   *
     1790   * @param boolean $alphaonly - Whether to only use alpha charaters
     1791   * @param integer $length - Length of random string to generate
     1792   * @return false|string
     1793   */
     1794  private function random_string($alphaonly = false, $length = 15) {
     1795    if ($alphaonly) {
     1796      return substr(str_shuffle(str_repeat($x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
     1797    } else {
     1798      return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
     1799    }
     1800  }
     1801
     1802  //---------------------------------------------------------------------------
     1803  /**
     1804   * Dump and Die.
     1805   *
     1806   * @param array $a Array to print out pretty
     1807   * @param bool $die Flag to die after dump or not
     1808   * @return string
     1809   * @since 3.2.0
     1810   */
     1811  private function dnd($a, $die = true) {
     1812    $dump = highlight_string("<?php\n\$data =\n" . var_export($a, true) . ";\n?>");
     1813    if ($die) die($dump);
     1814    else return $dump;
     1815  }
    18991816}
  • chordpress/trunk/languages/chordpress.pot

    r2996248 r3067783  
    1 # Copyright (C) 2023 George Lewe
     1# Copyright (C) 2024 George Lewe
    22# This file is distributed under the same license as the Lewe ChordPress plugin.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Lewe ChordPress 3.6.0\n"
     5"Project-Id-Version: Lewe ChordPress 3.6.1\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/chordpress\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2023-11-15T10:11:19+01:00\n"
     12"POT-Creation-Date: 2024-04-09T17:41:13+02:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.4.0\n"
     
    12201220msgstr ""
    12211221
    1222 #: includes/class-chordpress-renderer.php:592
     1222#: includes/class-chordpress-renderer.php:595
    12231223msgid "Font"
    12241224msgstr ""
    12251225
    1226 #: includes/class-chordpress-renderer.php:602
    1227 #: includes/class-chordpress-renderer.php:622
     1226#: includes/class-chordpress-renderer.php:605
     1227#: includes/class-chordpress-renderer.php:625
    12281228msgid "Transpose"
    12291229msgstr ""
    12301230
    1231 #: includes/class-chordpress-renderer.php:623
     1231#: includes/class-chordpress-renderer.php:626
    12321232msgid "Only works for international key names"
    12331233msgstr ""
    12341234
    1235 #: includes/class-chordpress-renderer.php:642
     1235#: includes/class-chordpress-renderer.php:645
    12361236msgid "Print"
    12371237msgstr ""
    12381238
    1239 #: includes/class-chordpress-renderer.php:678
     1239#: includes/class-chordpress-renderer.php:681
    12401240msgid "Composer"
    12411241msgstr ""
    12421242
    1243 #: includes/class-chordpress-renderer.php:679
     1243#: includes/class-chordpress-renderer.php:682
    12441244msgid "Artist"
    12451245msgstr ""
    12461246
    1247 #: includes/class-chordpress-renderer.php:680
     1247#: includes/class-chordpress-renderer.php:683
    12481248msgid "Year"
    12491249msgstr ""
    12501250
    1251 #: includes/class-chordpress-renderer.php:681
     1251#: includes/class-chordpress-renderer.php:684
    12521252msgid "Album"
    12531253msgstr ""
    12541254
    1255 #: includes/class-chordpress-renderer.php:684
     1255#: includes/class-chordpress-renderer.php:687
    12561256msgid "Key (original)"
    12571257msgstr ""
    12581258
    1259 #: includes/class-chordpress-renderer.php:685
     1259#: includes/class-chordpress-renderer.php:688
    12601260msgid "Key (transposed)"
    12611261msgstr ""
    12621262
    1263 #: includes/class-chordpress-renderer.php:692
     1263#: includes/class-chordpress-renderer.php:695
    12641264msgid "Time"
    12651265msgstr ""
    12661266
    1267 #: includes/class-chordpress-renderer.php:693
     1267#: includes/class-chordpress-renderer.php:696
    12681268msgid "Tempo"
    12691269msgstr ""
    12701270
    1271 #: includes/class-chordpress-renderer.php:694
     1271#: includes/class-chordpress-renderer.php:697
    12721272msgid "Capo"
    12731273msgstr ""
    12741274
    1275 #: includes/class-chordpress-renderer.php:728
     1275#: includes/class-chordpress-renderer.php:731
    12761276msgid "These known chords are used in this song"
    12771277msgstr ""
    12781278
    1279 #: includes/class-chordpress-renderer.php:844
     1279#: includes/class-chordpress-renderer.php:845
    12801280msgid "Missing square bracket in line"
    12811281msgstr ""
  • chordpress/trunk/makepot.cmd

    r2877462 r3067783  
    1 D:\xampp8.1.12\php\php.exe D:/wp-cli.phar i18n make-pot . languages/chordpress.pot --slug=chordpress --include="*.php,admin/*.php,admin/partials/*.php,includes/*.php,public/*.php,public/partials/*.php"
     1D:\xampp8.2.12\php\php.exe D:/wp-cli.phar i18n make-pot . languages/chordpress.pot --slug=chordpress --include="*.php,admin/*.php,admin/partials/*.php,includes/*.php,public/*.php,public/partials/*.php"
  • chordpress/trunk/readme.txt

    r2996248 r3067783  
    44Tags: chordpro,chord,chords,lyrics,music,notes,sheet,sound,guitar
    55Requires at least: 4.0
    6 Tested up to: 6.4
    7 Stable tag: 3.6.0
     6Tested up to: 6.5
     7Stable tag: 3.6.1
    88Requires PHP: 5.2.4
    99License: GPLv3
     
    130130
    131131== Changelog ==
     132= 3.6.1 =
     133* 2024-04-09
     134* WordPress 6.5 compatibility
     135* Added '-' as allowed chord prefix
     136
    132137= 3.6.0 =
    133138* 2023-11-15
  • chordpress/trunk/uninstall.php

    r2996248 r3067783  
    1414 */
    1515if (!defined('WP_UNINSTALL_PLUGIN')) {
    16     exit;
     16  exit;
    1717}
    1818
     
    3232 */
    3333if (get_option($pname . '_checkbox_uninstall_delete_options')) {
    34     $options = array(
    35         $pname . '_checkbox_fixed_interaction',
    36         $pname . '_checkbox_hide_album',
    37         $pname . '_checkbox_hide_artist',
    38         $pname . '_checkbox_hide_chords',
    39         $pname . '_checkbox_hide_comments',
    40         $pname . '_checkbox_hide_composer',
    41         $pname . '_checkbox_hide_print',
    42         $pname . '_checkbox_hide_subtitle',
    43         $pname . '_checkbox_hide_title',
    44         $pname . '_checkbox_hide_transpose',
    45         $pname . '_checkbox_hide_year',
    46         $pname . '_checkbox_hb_notation',
    47         $pname . '_checkbox_show_chord_sheet',
    48         $pname . '_checkbox_show_jtab_sheet',
    49         $pname . '_checkbox_show_chord_sheet_on_top',
    50         $pname . '_checkbox_show_numeric_transpose',
    51         $pname . '_select_title_level',
    52         $pname . '_select_subtitle_level',
    53         $pname . '_text_meta_style',
    54         $pname . '_text_chord_style',
    55         $pname . '_text_lyrics_style',
    56         $pname . '_text_comment_style',
    57         $pname . '_text_chorus_style',
    58         $pname . '_text_verse_style',
    59         $pname . '_text_line_style',
    60         $pname . '_text_chord_backgroundColor',
    61         $pname . '_number_chord_barreChordRadius',
    62         $pname . '_text_chord_barreChordStrokeColor',
    63         $pname . '_number_chord_barreChordStrokeWidth',
    64         $pname . '_number_chord_canvasWidth',
    65         $pname . '_text_chord_color',
    66         $pname . '_number_chord_emptyStringIndicatorSize',
    67         $pname . '_checkbox_chord_fixedDiagramPosition',
    68         $pname . '_text_chord_fontFamily',
    69         $pname . '_text_chord_fretColor',
    70         $pname . '_text_chord_fretLabelColor',
    71         $pname . '_text_chord_fretLabelColor',
    72         $pname . '_select_chord_fretLabelPosition',
    73         $pname . '_number_chord_fretLabelFontSize',
    74         $pname . '_number_chord_frets',
    75         $pname . '_number_chord_fretSize',
    76         $pname . '_number_chord_nutSize',
    77         $pname . '_text_chord_nutColor',
    78         $pname . '_text_chord_nutStrokeColor',
    79         $pname . '_number_chord_nutStrokeWidth',
    80         $pname . '_text_chord_nutTextColor',
    81         $pname . '_number_chord_nutTextSize',
    82         $pname . '_number_chord_position',
    83         $pname . '_number_chord_sidePadding',
    84         $pname . '_text_chord_stringColor',
    85         $pname . '_select_chord_strings',
    86         $pname . '_number_chord_strokeWidth',
    87         $pname . '_select_chord_style',
    88         $pname . '_number_chord_titleBottomMargin',
    89         $pname . '_text_chord_titleColor',
    90         $pname . '_number_chord_titleFontSize',
    91         $pname . '_number_chord_topFretWidth',
    92         $pname . '_text_chord_tuning',
    93         $pname . '_text_chord_tuningsColor',
    94         $pname . '_number_chord_tuningsFontSize',
    95     );
     34  $options = array(
     35    $pname . '_checkbox_fixed_interaction',
     36    $pname . '_checkbox_hide_album',
     37    $pname . '_checkbox_hide_artist',
     38    $pname . '_checkbox_hide_chords',
     39    $pname . '_checkbox_hide_comments',
     40    $pname . '_checkbox_hide_composer',
     41    $pname . '_checkbox_hide_print',
     42    $pname . '_checkbox_hide_subtitle',
     43    $pname . '_checkbox_hide_title',
     44    $pname . '_checkbox_hide_transpose',
     45    $pname . '_checkbox_hide_year',
     46    $pname . '_checkbox_hb_notation',
     47    $pname . '_checkbox_show_chord_sheet',
     48    $pname . '_checkbox_show_jtab_sheet',
     49    $pname . '_checkbox_show_chord_sheet_on_top',
     50    $pname . '_checkbox_show_numeric_transpose',
     51    $pname . '_select_title_level',
     52    $pname . '_select_subtitle_level',
     53    $pname . '_text_meta_style',
     54    $pname . '_text_chord_style',
     55    $pname . '_text_lyrics_style',
     56    $pname . '_text_comment_style',
     57    $pname . '_text_chorus_style',
     58    $pname . '_text_verse_style',
     59    $pname . '_text_line_style',
     60    $pname . '_text_chord_backgroundColor',
     61    $pname . '_number_chord_barreChordRadius',
     62    $pname . '_text_chord_barreChordStrokeColor',
     63    $pname . '_number_chord_barreChordStrokeWidth',
     64    $pname . '_number_chord_canvasWidth',
     65    $pname . '_text_chord_color',
     66    $pname . '_number_chord_emptyStringIndicatorSize',
     67    $pname . '_checkbox_chord_fixedDiagramPosition',
     68    $pname . '_text_chord_fontFamily',
     69    $pname . '_text_chord_fretColor',
     70    $pname . '_text_chord_fretLabelColor',
     71    $pname . '_text_chord_fretLabelColor',
     72    $pname . '_select_chord_fretLabelPosition',
     73    $pname . '_number_chord_fretLabelFontSize',
     74    $pname . '_number_chord_frets',
     75    $pname . '_number_chord_fretSize',
     76    $pname . '_number_chord_nutSize',
     77    $pname . '_text_chord_nutColor',
     78    $pname . '_text_chord_nutStrokeColor',
     79    $pname . '_number_chord_nutStrokeWidth',
     80    $pname . '_text_chord_nutTextColor',
     81    $pname . '_number_chord_nutTextSize',
     82    $pname . '_number_chord_position',
     83    $pname . '_number_chord_sidePadding',
     84    $pname . '_text_chord_stringColor',
     85    $pname . '_select_chord_strings',
     86    $pname . '_number_chord_strokeWidth',
     87    $pname . '_select_chord_style',
     88    $pname . '_number_chord_titleBottomMargin',
     89    $pname . '_text_chord_titleColor',
     90    $pname . '_number_chord_titleFontSize',
     91    $pname . '_number_chord_topFretWidth',
     92    $pname . '_text_chord_tuning',
     93    $pname . '_text_chord_tuningsColor',
     94    $pname . '_number_chord_tuningsFontSize',
     95  );
    9696
    97     foreach ($options as $option) {
    98         delete_option($option);
    99     }
     97  foreach ($options as $option) {
     98    delete_option($option);
     99  }
    100100}
    101101
     
    105105 */
    106106if (get_option($pname . '_checkbox_uninstall_delete_chordposts')) {
    107     $args = array(
    108         'post_type' => 'guitar_chord',
    109         'posts_per_page' => -1
    110     );
    111     $query = new WP_Query ($args);
    112     while ($query->have_posts()) {
    113         $query->the_post();
    114         $id = get_the_ID();
    115         wp_delete_post($id, true);
    116     }
    117     wp_reset_postdata();
     107  $args = array(
     108    'post_type' => 'guitar_chord',
     109    'posts_per_page' => -1
     110  );
     111  $query = new WP_Query ($args);
     112  while ($query->have_posts()) {
     113    $query->the_post();
     114    $id = get_the_ID();
     115    wp_delete_post($id, true);
     116  }
     117  wp_reset_postdata();
    118118
    119     global $wp_post_types;
    120     if (isset($wp_post_types['guitar_chord'])) {
    121         unset($wp_post_types['guitar_chord']);
    122     }
     119  global $wp_post_types;
     120  if (isset($wp_post_types['guitar_chord'])) {
     121    unset($wp_post_types['guitar_chord']);
     122  }
    123123}
Note: See TracChangeset for help on using the changeset viewer.