@@ -264,6 +264,20 @@ class PhraseMaker {
264264 * @type {boolean }
265265 */
266266 this . lyricsON = false ;
267+
268+ /**
269+ * Number of beats per measure (from meter block)
270+ * @type {number }
271+ * @private
272+ */
273+ this . _meterBeats = 4 ;
274+
275+ /**
276+ * Note value that gets the beat (from meter block)
277+ * @type {number }
278+ * @private
279+ */
280+ this . _meterNoteValue = 4 ;
267281 }
268282
269283 /**
@@ -357,6 +371,67 @@ class PhraseMaker {
357371 }
358372 }
359373 }
374+ /**
375+ * Gets the current meter settings from the turtle's singer.
376+ * Updates internal meter properties for bar line calculations.
377+ * @private
378+ */
379+ _getCurrentMeter ( ) {
380+ // Access meter from the turtle's singer
381+ if ( this . activity . turtles && this . activity . turtles . ithTurtle ( 0 ) ) {
382+ const turtle = this . activity . turtles . ithTurtle ( 0 ) ;
383+ if ( turtle . singer ) {
384+ // Get the most recent meter setting
385+ if ( turtle . singer . beatsPerMeasure && turtle . singer . beatsPerMeasure . length > 0 ) {
386+ this . _meterBeats = turtle . singer . beatsPerMeasure [ turtle . singer . beatsPerMeasure . length - 1 ] ;
387+ }
388+ if ( turtle . singer . noteValuePerBeat && turtle . singer . noteValuePerBeat . length > 0 ) {
389+ this . _meterNoteValue = turtle . singer . noteValuePerBeat [ turtle . singer . noteValuePerBeat . length - 1 ] ;
390+ }
391+ }
392+ }
393+ }
394+
395+ /**
396+ * Determines if a column position should have a bar line.
397+ * @param {number } columnIndex - The index of the column to check.
398+ * @returns {boolean } True if this column should have a bar line.
399+ * @private
400+ */
401+ _isBarLine ( columnIndex ) {
402+ if ( columnIndex === 0 ) {
403+ return true ; // First measure always starts with a bar line
404+ }
405+
406+ this . _getCurrentMeter ( ) ;
407+
408+ // Calculate the cumulative note value up to this position
409+ let cumulativeValue = 0 ;
410+ for ( let i = 0 ; i < columnIndex ; i ++ ) {
411+ if ( this . _noteValueRow && this . _noteValueRow . cells [ i ] ) {
412+ const noteValue = parseFloat ( this . _noteValueRow . cells [ i ] . getAttribute ( "alt" ) ) || 0 ;
413+ cumulativeValue += noteValue ;
414+ } else {
415+ // Fallback for tuplet cases
416+ const noteValue = 1 / ( this . _notesToPlay [ i ] && this . _notesToPlay [ i ] [ 1 ] ? this . _notesToPlay [ i ] [ 1 ] : 4 ) ;
417+ cumulativeValue += noteValue ;
418+ }
419+ }
420+
421+ // Calculate measure duration in whole note units
422+ // meterBeats * (4 / meterNoteValue) gives us the measure duration
423+ const measureDuration = this . _meterBeats * ( 4 / this . _meterNoteValue ) ;
424+
425+ // Convert cumulative value to quarter note units for easier calculation
426+ const positionInQuarters = cumulativeValue * 4 ;
427+ const measureInQuarters = measureDuration ;
428+
429+ // Check if we're at a measure boundary (with tolerance for floating point errors)
430+ const remainder = positionInQuarters % measureInQuarters ;
431+
432+
433+ return Math . abs ( remainder ) < 0.001 || Math . abs ( remainder - measureInQuarters ) < 0.001 ;
434+ }
360435
361436 /**
362437 * Clears block references within the PhraseMaker.
@@ -504,6 +579,8 @@ class PhraseMaker {
504579 this . _notesToPlay = [ ] ;
505580 this . _matrixHasTuplets = false ;
506581
582+ this . _getCurrentMeter ( ) ;
583+
507584 // Add the buttons to the top row.
508585
509586 widgetWindow . onclose = ( ) => {
@@ -3024,7 +3101,7 @@ class PhraseMaker {
30243101 cell . innerHTML = tupletValue ;
30253102 cell . style . backgroundColor = platformColor . tupletBackground ;
30263103
3027- // And a span in the note value column too.
3104+ // Add a span in the note value column too.
30283105 const noteValueRow = this . _noteValueRow ;
30293106 cell = noteValueRow . insertCell ( ) ;
30303107 cell . colSpan = numberOfNotes ;
@@ -3038,6 +3115,12 @@ class PhraseMaker {
30383115 cell . innerHTML = noteValueToDisplay ;
30393116 cell . style . backgroundColor = platformColor . rhythmcellcolor ;
30403117 this . _matrixHasTuplets = true ;
3118+
3119+ const currentColumnIndex = noteValueRow . cells . length - 1 ;
3120+ if ( this . _isBarLine ( currentColumnIndex ) ) {
3121+ cell . style . borderLeft = "3px solid #333333" ;
3122+ cell . style . paddingLeft = "2px" ;
3123+ }
30413124 }
30423125
30433126 /**
@@ -3127,6 +3210,11 @@ class PhraseMaker {
31273210 cell . style . color = platformColor . textColor ;
31283211 cell . setAttribute ( "alt" , noteValue ) ;
31293212
3213+ if ( this . _isBarLine ( j ) ) {
3214+ cell . style . borderLeft = "3px solid #333333" ;
3215+ cell . style . paddingLeft = "2px" ;
3216+ }
3217+
31303218 if ( this . _matrixHasTuplets ) {
31313219 // We may need to insert some blank cells in the extra rows
31323220 // added by tuplets.
0 commit comments