Browse Source

more work on variants

master
Cerys 4 weeks ago
parent
commit
d25f49bcb9
  1. 5
      App/Wrappers/TwigWrapper.php
  2. 3
      Configuration/Configuration.yaml
  3. 1
      Localisation/en-GB.yaml
  4. 53
      Public/API/V1/GetBasicABC.php
  5. 187
      Public/Static/CSS/ThirdParty/abcjs-audio.css
  6. 31
      Public/Static/JS/General/ABCWrapper.js
  7. 2
      Public/Static/JS/General/AlgoliaInteractions.js
  8. 3
      Public/Static/JS/ThirdParty/ABCJS.js
  9. 3
      Public/Static/JS/ThirdParty/abcjs-basic-min.js
  10. 26516
      Public/Static/JS/ThirdParty/abcjs-basic.js
  11. 3
      Public/Static/JS/ThirdParty/abcjs-plugin-min.js
  12. 15
      Templates/Bases/StandardWebPage.html.twig
  13. 90
      Templates/Pages/tune/uuid.html.twig

5
App/Wrappers/TwigWrapper.php

@ -35,7 +35,10 @@ class TwigWrapper
$this->twig->addGlobal('_SESSION_', $_SESSION);
$this->twig->addGlobal('_ALGOLIA_INDEX_NAME_', Configuration::GetConfig("Algolia", "IndexName"));
$this->twig->addGlobal('_ALGOLIA_INDEXES_', [
"Tunes" => Configuration::GetConfig("Algolia", "Indexes", "Tunes"),
"Dances" => Configuration::GetConfig("Algolia", "Indexes", "Dances"),
]);
$this->twig->addGlobal('_ALGOLIA_APP_ID_', Configuration::GetConfig("Algolia", "AppID"));
$this->twig->addGlobal('_ALGOLIA_SEARCH_ONLY_API_KEY_', Configuration::GetConfig("Algolia", "APIKeys", "SearchOnly"));

3
Configuration/Configuration.yaml

@ -2,6 +2,9 @@
Algolia:
AppID: ;ALGOLIA__APP_ID
IndexName: FolkTunes_LIVE
Indexes:
Tunes: FolkTunes_LIVE
Dances: Dances_LIVE
APIKeys:
SearchOnly: ;ALGOLIA__API_SEARCH_KEY
Write: ;ALGOLIA__API_WRITE_KEY

1
Localisation/en-GB.yaml

@ -119,6 +119,7 @@ Number of Parts: Number of Parts
##################################################
# S
##################################################
Suggest another: Suggest another

53
Public/API/V1/GetBasicABC.php

@ -0,0 +1,53 @@
<?php
use App\Dataclasses\DatabaseFolkTuneDetails;
use App\Dataclasses\TuneVariant;
use App\Wrappers\DatabaseInteractions;
use App\Wrappers\SQLQueryBuilderWrapper;
$tuneDir = __DIR__ . '/../../../LocalStorage/Tunes';
$targetTuneVariantID = $_GET['tune-variant-id'];
$db = new DatabaseInteractions();
$variantDetails = $db->RunOneSelect(
queryBuilder: SQLQueryBuilderWrapper::SELECT_ONE(
table: 'TuneVariants',
id: $targetTuneVariantID
)
->cols([
'T.ID AS TuneVariantID',
'T.TuneID AS TuneID',
"CONCAT('[', GROUP_CONCAT(
CONCAT(
'{\"TimeSignature\":', JSON_QUOTE(T_TVP.TimeSignature), ',',
'\"KeySignature\":', JSON_QUOTE(T_TVP.KeySignature), ',',
'\"ABCNotation\":', JSON_QUOTE(T_TVP.ABCNotation), '}'
)
), ']') AS Parts"
])
->join(
join: 'INNER',
spec: 'TuneVariantParts AS T_TVP',
cond: 'T.ID = T_TVP.TuneVariantID'
)
->groupBy(spec: [
'T.ID',
])
);
$tuneDetails = $db->RunOneSelect(
queryBuilder: SQLQueryBuilderWrapper::SELECT_ONE(
table: 'Tunes',
id: $variantDetails['TuneID']
)
);
$tuneDetails = new DatabaseFolkTuneDetails($tuneDetails);
$variantDetails = new TuneVariant($tuneDetails, $variantDetails);
header(header: "Content-type: text/text");
echo $variantDetails->Build();
die();

187
Public/Static/CSS/ThirdParty/abcjs-audio.css

@ -0,0 +1,187 @@
/* Some basic CSS to make the Audio controls in abcjs presentable. */
.abcjs-inline-audio {
height: 26px;
padding: 0 5px;
border-radius: 3px;
background-color: #424242;
display: flex;
align-items: center;
box-sizing: border-box;
}
.abcjs-inline-audio.abcjs-disabled {
opacity: 0.5;
}
.abcjs-inline-audio .abcjs-btn {
display: block;
width: 28px;
height: 34px;
margin-right: 2px;
padding: 7px 4px;
background: none !important;
border: 1px solid transparent;
box-sizing: border-box;
line-height: 1;
}
.abcjs-btn g {
fill: #f4f4f4;
stroke: #f4f4f4;
}
.abcjs-inline-audio .abcjs-btn:hover g {
fill: #cccccc;
stroke: #cccccc;
}
.abcjs-inline-audio .abcjs-midi-selection.abcjs-pushed {
border: 1px solid #cccccc;
background-color: #666666;
box-sizing: border-box;
}
.abcjs-inline-audio .abcjs-midi-loop.abcjs-pushed {
border: 1px solid #cccccc;
background-color: #666666;
box-sizing: border-box;
}
.abcjs-inline-audio .abcjs-midi-reset.abcjs-pushed {
border: 1px solid #cccccc;
background-color: #666666;
box-sizing: border-box;
}
.abcjs-inline-audio .abcjs-midi-start .abcjs-pause-svg {
display: none;
}
.abcjs-inline-audio .abcjs-midi-start .abcjs-loading-svg {
display: none;
}
.abcjs-inline-audio .abcjs-midi-start.abcjs-pushed .abcjs-play-svg {
display: none;
}
.abcjs-inline-audio .abcjs-midi-start.abcjs-loading .abcjs-play-svg {
display: none;
}
.abcjs-inline-audio .abcjs-midi-start.abcjs-pushed .abcjs-pause-svg {
display: block;
}
.abcjs-inline-audio .abcjs-midi-progress-background {
background-color: #424242;
height: 10px;
border-radius: 5px;
border: 2px solid #cccccc;
margin: 0 8px 0 15px;
position: relative;
flex: 1;
padding: 0;
box-sizing: border-box;
}
.abcjs-inline-audio .abcjs-midi-progress-indicator {
width: 20px;
margin-left: -10px; /* half of the width */
height: 14px;
background-color: #f4f4f4;
position: absolute;
display: inline-block;
border-radius: 6px;
top: -4px;
left: 0;
box-sizing: border-box;
}
.abcjs-inline-audio .abcjs-midi-clock {
margin-left: 4px;
margin-top: 1px;
margin-right: 2px;
display: inline-block;
font-family: sans-serif;
font-size: 16px;
box-sizing: border-box;
color: #f4f4f4;
}
.abcjs-inline-audio .abcjs-tempo-wrapper {
font-size: 10px;
color: #f4f4f4;
box-sizing: border-box;
display: flex;
align-items: center;
}
.abcjs-inline-audio .abcjs-midi-tempo {
border-radius: 2px;
border: none;
margin: 0 2px 0 4px;
width: 42px;
padding-left: 2px;
box-sizing: border-box;
}
.abcjs-inline-audio .abcjs-loading .abcjs-loading-svg {
display: inherit;
}
.abcjs-inline-audio .abcjs-loading {
outline: none;
animation-name: abcjs-spin;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.abcjs-inline-audio .abcjs-loading-svg circle {
stroke: #f4f4f4;
}
@keyframes abcjs-spin {
from {transform:rotate(0deg);}
to {transform:rotate(360deg);}
}
/* Adding the class "abcjs-large" will make the control easier on a touch device. */
.abcjs-large .abcjs-inline-audio {
height: 52px;
}
.abcjs-large .abcjs-btn {
width: 56px;
height: 52px;
font-size: 28px;
padding: 6px 8px;
}
.abcjs-large .abcjs-midi-progress-background {
height: 20px;
border: 4px solid #cccccc;
}
.abcjs-large .abcjs-midi-progress-indicator {
height: 28px;
top: -8px;
width: 40px;
}
.abcjs-large .abcjs-midi-clock {
font-size: 32px;
margin-right: 10px;
margin-left: 10px;
margin-top: -1px;
}
.abcjs-large .abcjs-midi-tempo {
font-size: 20px;
width: 50px;
}
.abcjs-large .abcjs-tempo-wrapper {
font-size: 20px;
}
.abcjs-css-warning {
display: none;
}

31
Public/Static/JS/General/ABCWrapper.js

@ -1,31 +0,0 @@
function RenderABC(containerID, targetTuneID)
{
API_GET("/V1/GetABCFile.php?tune-variant-id=" + targetTuneID).then(payload => {
const tunes = ABCJS.renderAbc(
containerID,
payload,
{
add_classes: true,
format: {
gchordfont: "Atkinson Hyperlegible",
annotationfont: "Atkinson Hyperlegible",
headerfont: "Atkinson Hyperlegible",
infofont: "Atkinson Hyperlegible",
repeatfont: "Atkinson Hyperlegible",
tempofont: "Atkinson Hyperlegible",
titlefont: "Atkinson Hyperlegible",
voicefont: "Atkinson Hyperlegible",
wordsfont: "Atkinson Hyperlegible",
},
}
);
document.getElementById('RawABCReadout').innerHTML = payload;
})
.catch(error => {
console.log(error)
});
}

2
Public/Static/JS/General/AlgoliaInteractions.js

@ -6,7 +6,7 @@ function searchTunes(query) {
resultsDiv.innerHTML = "";
index.search(query).then(({ hits }) => {
tuneIndex.search(query).then(({ hits }) => {
if (hits.length > 0) {
hits.forEach(hit => {
const tuneDiv = document.createElement("div");

3
Public/Static/JS/ThirdParty/ABCJS.js

File diff suppressed because one or more lines are too long

3
Public/Static/JS/ThirdParty/abcjs-basic-min.js

File diff suppressed because one or more lines are too long

26516
Public/Static/JS/ThirdParty/abcjs-basic.js

File diff suppressed because one or more lines are too long

3
Public/Static/JS/ThirdParty/abcjs-plugin-min.js

File diff suppressed because one or more lines are too long

15
Templates/Bases/StandardWebPage.html.twig

@ -8,16 +8,14 @@
<link rel="stylesheet" href="/Static/CSS/Mapper.css">
<link rel="stylesheet" href="/Static/CSS/Themes/Light.css">
<script src="https://cdn.jsdelivr.net/npm/algoliasearch/dist/algoliasearch-lite.umd.js"></script>
<script src="/Static/JS/ThirdParty/ABCJS.js"></script>
<script>
const client = algoliasearch('{{ _ALGOLIA_APP_ID_ }}', '{{ _ALGOLIA_SEARCH_ONLY_API_KEY_ }}');
const index = client.initIndex('{{ _ALGOLIA_INDEX_NAME_ }}');
const tuneIndex = client.initIndex('{{ _ALGOLIA_INDEXES_.Tunes }}');
const danceIndex = client.initIndex('{{ _ALGOLIA_INDEXES_.Dances }}');
</script>
<script src="/Static/JS/General/ABCWrapper.js"></script>
<script src="/Static/JS/General/AlgoliaInteractions.js"></script>
<script src="/Static/JS/General/APIInteractions.js"></script>
@ -27,6 +25,15 @@
<div class="wrapper">
<div class="main_container">
<nav>
<ul>
<li><a href="/">Home</a></li>
<li>
<input type="text" placeholder="Search for tunes...">
</li>
<li style="float:right"><a class="active" href="#about">About</a></li>
</ul>
</nav>
<main>
{% block content %}{% endblock %}
</main>

90
Templates/Pages/tune/uuid.html.twig

@ -2,6 +2,11 @@
{% block content %}
<script src="/Static/JS/ThirdParty/abcjs-basic.js"></script>
<!--<script src="/Static/JS/ThirdParty/abcjs-plugin-min.js"></script>-->
<link rel="stylesheet" href="/Static/CSS/ThirdParty/abcjs-audio.css">
<div class="InnerContent">
<h1>{{ "Variants of"|translate }} "{{ TuneDetails.Title }}"</h1>
{% for x in TuneVariants %}
@ -27,17 +32,17 @@
</div>
</div>
<div class="center">
<div id="music-container--{{ x.ID }}"></div>
<div id="NotationContainer--{{ x.ID }}"></div>
<div>
<h2>{{ "ABC Notation"|translate }}</h2>
<pre id="RawABCReadout">
<pre id="RawABCReadout--{{ x.ID }}">
</pre>
</div>
</div>
<div class="right">
<h2>{{ "Audio"|translate }}</h2>
<audio id="midiPlayer" controls></audio>
<div id="MIDI--{{ x.ID }}"></div>
</div>
</div>
@ -47,7 +52,17 @@
</div>
<div class="InnerContent">
<h1>{{ "Dances for"|translate }} "{{ TuneDetails.Title }}"</h1>
<h1>
{{ "Dances for"|translate }}
"{{ TuneDetails.Title }}"
<span>
<sup>
<a href="/tunes/{{ TuneDetails.ID }}/suggest-dance">
{{ "Suggest another"|translate }}
</a>
</sup>
</span>
</h1>
{% for x in Dances %}
<div>
<button class="accordion">{{ x.Title }}</button>
@ -96,9 +111,70 @@
}
</script>
<script>
{% for x in TuneVariants %}
RenderABC("music-container--{{ x.ID }}", '{{ x.ID }}');
{% endfor %}
if (!window.ABCJS) {
console.error("ABCJS library failed to load.");
}
</script>
<script>
document.addEventListener("DOMContentLoaded", function () {
function RenderABC(targetTuneID) {
API_GET("/V1/GetABCFile.php?tune-variant-id=" + targetTuneID)
.then(payload => {
// Ensure required DOM elements exist
const notationContainer = document.getElementById("NotationContainer--" + targetTuneID);
const rawABCContainer = document.getElementById("RawABCReadout--" + targetTuneID);
const midiContainer = document.getElementById("MIDI--" + targetTuneID);
if (!notationContainer || !rawABCContainer || !midiContainer) {
console.error(`Missing DOM elements for targetTuneID: ${targetTuneID}`);
return;
}
console.log(window.ABCJS);
// Render the ABC notation
const tunes = window.ABCJS.renderAbc(
notationContainer.id,
payload,
{
add_classes: true,
format: {
gchordfont: "Atkinson Hyperlegible",
annotationfont: "Atkinson Hyperlegible",
headerfont: "Atkinson Hyperlegible",
infofont: "Atkinson Hyperlegible",
repeatfont: "Atkinson Hyperlegible",
tempofont: "Atkinson Hyperlegible",
titlefont: "Atkinson Hyperlegible",
voicefont: "Atkinson Hyperlegible",
wordsfont: "Atkinson Hyperlegible",
},
}
);
// Display raw ABC notation
rawABCContainer.innerHTML = payload;
window.ABCJS.startAnimation(notationContainer.id, tunes[0], {
showCursor: true,
});
})
.catch(error => {
console.error("Error fetching ABC data:", error);
});
}
{% for x in TuneVariants %}
RenderABC('{{ x.ID }}');
{% endfor %}
});
</script>
{% endblock %}
Loading…
Cancel
Save