draw new object onto existing canvas in Scheme using paint-callback - oop

Some background, I'm making Space Invaders as a project in a CS class. Currently I'm working on making the player ship shoot projectiles, not worrying about collisions, just spawning projectiles.
(define projectile%
(class object%
(init-field [image (make-bitmap 10 10)]
[x 100]
[y 100]
[speed 1])
(define/public (get-image) image)
(define/private (move-up)
(set! y (- y speed)))
(define/public (render dc)
(let ((w (send image get-width))
(h (send image get-height)))
(move-up)
(send dc translate (+ x (/ w 2)) (+ y (/ h 2)))
(send dc draw-bitmap image (- (/ w 2)) (- (/ h 2)))
(send dc translate (- (+ x (/ w 2))) (- (+ y (/ h 2))))))
(super-new)))
(define player-ship%
(class object%
(init-field [image (make-bitmap 30 25)]
[x 400]
[y 300]
[speed 3])
(define/public (get-image) image)
(define/public (get-x) x)
(define/public (get-y) y)
(define/private (shoot)
;Spawning a projectile would go here
(define/public (render dc)
(let ((w (send image get-width))
(h (send image get-height)))
(send dc translate (+ x (/ w 2)) (+ y (/ h 2)))
(send dc draw-bitmap image (- (/ w 2)) (- (/ h 2)))
(send dc translate (- (+ x (/ w 2))) (- (+ y (/ h 2))))))
(define/public (key-down key-code)
(cond ((equal? key-code 'left) (move-left))
((equal? key-code 'right) (move-right))
((equal? key-code 'up) (shoot))))
(super-new)))
Those are the two relevant classes, some failed code for spawning a projectile removed.
Some code for how I'm drawing the window and stuff:
(define *my-game-canvas*
(new game-canvas%
[parent *game-window*]
[paint-callback (lambda (canvas dc)
(begin
(send *my-ship* render dc)
(send *ship-projectile* render dc)))]
[keyboard-handler (lambda (key-event)
(let ((key-code (send key-event get-key-code)))
(if (not (equal? key-code 'release))
(send *my-ship* key-down key-code))))]))
(define *my-timer* (new timer%
[notify-callback (lambda ()
(send *my-game-canvas* refresh))]))
(make-ship-projectile (send *ship-projectile* get-image))
;creating a projectile just seeing whether they work or not
(make-ship (send *my-ship* get-image))
The make-ship and make-ship-projectile functions work as follows:
(define (make-ship-projectile bitmap-target)
(let ((dc (new bitmap-dc% [bitmap bitmap-target])))
(send dc set-brush (make-object brush% "black" 'solid))
(send dc draw-ellipse 0 0 10 10)))
The problem arises when I try to create a new projectile with the shoot method in player-ship%, it simply doesn't work. I'm currently under the assumption that it doesn't work due to the new projectile not being in my-game-canvas's paint-callback, however, I do not know how to update that attribute. Am I approaching it from the wrong direction?

Yes, if the drawing of the projectile is not triggered from paint-callback (or another function/method called from it), it will not be displayed in the canvas when the canvas is refreshed.
One possibility is to have a list of existing projectiles (possibly an attribute in player-ship%), and paint-callback should trigger (possibly via player-ship%'s render method, or via a different method in player-ship% like render-projectiles that is called from the paint-callback) the display of all these projectiles in the canvas. When a new projectile is shot from the ship, it should be added to the list of existing projectiles and when the projectile hits something or escapes the board, it should be removed from this list.

Related

Two racket modules colliding

I am requiring two modules to my file:
(require sicp) ; contains set-car! and set-cdr!
(require (planet dyoo/sicp-concurrency:1:2/sicp-concurrency)) ; contains procedures parallel-execute and test-and-set!
Problem: both libraries use different flavors of scheme. The sicp-concurrency uses mzscheme. Requiring this module prevented me from using else in a cond clause.
Is there a way to prevent the features of mzscheme in sicp-concurrency while still making use of the procedures I needed?
I have updated Danny Yoo's code to Racket 7.
Get the new file "sicp-concurrency.rkt" here:
https://gist.github.com/soegaard/d32e12d89705c774b71ee78ef930a4bf
Save the file in the same folder as your program file.
Here is an example of use:
#lang sicp
(#%require "sicp-concurrency.rkt")
(define (test-1)
(define x 10)
(parallel-execute (lambda () (set! x (* x x)))
(lambda () (set! x (+ x 1))))
x)
(define (test-2)
(define x 10)
(define s (make-serializer))
(parallel-execute (s (lambda () (set! x (* x x))))
(s (lambda () (set! x (+ x 1)))))
x)
(test-1)
(test-1)
(test-1)
(test-1)
(test-1)

Clojurescript: functional way to make a bouncing ball

I'm learning Clojurescript while comparing it to Javascript and rewritting some scripts.
In Javascript I've created a canvas with a ball in it, that when it gets to the canvas' borders, it bounces back. I've made the same in Clojurescript, it works, but I need to create atoms outside the function, so I can keep track of the state. If I want to create more balls, I will need to replicate those atoms. At that point the code will be ugly. How should I change the code so I can create multiple balls and each with it's own state?
Here is the Javascript code:
// Circle object
function Circle(pos_x, pos_y, radius, vel_x, vel_y){
// Starting variables
this.radius = radius;
this.pos_x = pos_x;
this.pos_y = pos_y;
this.vel_x = vel_x;
this.vel_y = vel_y;
// Draw circle on the canvas
this.draw = function(){
c.beginPath();
c.arc(this.pos_x, this.pos_y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = this.color;
c.lineWidth = 5;
c.fillStyle = this.color_fill;
c.fill();
c.stroke();
};
// Update the circle variables each time it is called
this.update = function(){
// Check if it goes out of the width
if(this.pos_x + this.radius > canvas.width || this.pos_x - this.radius < 0){
// Invert velocity = invert direction
this.vel_x = -this.vel_x;
}
// Check if it goies out of the height
if(this.pos_y + this.radius > canvas.height || this.pos_y - this.radius < 0){
this.vel_y = -this.vel_y;
}
// Apply velocity
this.pos_x += this.vel_x;
this.pos_y += this.vel_y;
// Draw circle
this.draw();
};
};
// Create a single circle
let one_circle = new Circle(300, 300, 20, 1, 1);
function animate(){
requestAnimationFrame(animate);
// Clear canvas
c.clearRect(0, 0, canvas.width, canvas.height);
// Update all the circles
one_circle.update();
}
animate();
Here is the Clojurescript code:
(def ball-x (atom 300))
(def ball-y (atom 300))
(def ball-vel-x (atom 1))
(def ball-vel-y (atom 1))
(defn ball
[pos-x pos-y radius]
(.beginPath c)
(.arc c pos-x pos-y radius 0 (* 2 Math/PI))
(set! (.-lineWidth c) 5)
(set! (.-fillStyle c) "red")
(.fill c)
(.stroke c))
(defn update-ball
[]
(if (or (> (+ #ball-x radius) (.-width canvas)) (< (- #ball-x radius) 0))
(reset! ball-vel-x (- #ball-vel-x)))
(if (or (> (+ #ball-y radius) (.-height canvas)) (< (- #ball-y radius) 60))
(reset! ball-vel-y (- #ball-vel-y)))
(reset! ball-x (+ #ball-x #ball-vel-x))
(reset! ball-y (+ #ball-y #ball-vel-y))
(ball #ball-x #ball-y 20))
(defn animate
[]
(.requestAnimationFrame js/window animate)
(update-ball))
(animate)
Edit: I've tried a new approach to the problem, but this doesn't work. The ball is created, but it doesn't move.
(defrecord Ball [pos-x pos-y radius vel-x vel-y])
(defn create-ball
[ball]
(.beginPath c)
(.arc c (:pos-x ball) (:pos-y ball) (:radius ball) 0 (* 2 Math/PI))
(set! (.-lineWidth c) 5)
(set! (.-fillStyle c) "red")
(.fill c)
(.stroke c))
(def balls (atom {}))
(reset! balls (Ball. 301 300 20 1 1))
(defn calculate-movement
[ball]
(let [pos-x (:pos-x ball)
pos-y (:pos-y ball)
radius (:radius ball)
vel-x (:vel-x ball)
vel-y (:vel-y ball)
new-ball (atom {:pos-x pos-x :pos-y pos-y :radius radius :vel-x vel-x :vel-y vel-y})]
; Check if out of boundaries - width
(if (or (> (+ pos-x radius) (.-width canvas)) (< (- pos-x radius) 0))
(swap! new-ball assoc :vel-x (- vel-x)))
; Check if out of boundaries - height
(if (or (> (+ pos-y radius) (.-height canvas)) (< (- pos-y radius) 60))
(swap! new-ball assoc :vel-y (- vel-y)))
; Change `pos-x` and `pos-y`
(swap! new-ball assoc :pos-x (+ pos-x (#new-ball :vel-x)))
(swap! new-ball assoc :pos-x (+ pos-y (#new-ball :vel-y)))
(create-ball #new-ball)
(println #new-ball)
#new-ball))
(defn animate
[]
(.requestAnimationFrame js/window animate)
(reset! balls (calculate-movement #balls)))
(animate)
I'd maintain all of the balls as a collection in an atom. Each ball could be represented as a defrecord, but here we'll just keep them as maps. Let's define two balls:
(def balls (atom [{:pos-x 300
:pos-y 300
:radius 20
:vel-x 1
:vel-y 1}
{:pos-x 500
:pos-y 200
:radius 20
:vel-x -1
:vel-y 1}]))
I'd define a function that can draw a single ball:
(defn draw-ball [ball]
(let [{:keys [pos-x pos-y radius]} ball]
(set! (.-fillStyle c) "black")
(.beginPath c)
(.arc c pos-x pos-y radius 0 (* 2 Math/PI))
(.fill c)))
While we are at it, let's define a function to clear the canvas:
(defn clear-canvas []
(.clearRect c 0 0 (.-width canvas) (.-height canvas)))
Now, let's define a function that can update a single ball:
(defn update-ball [ball]
(let [{:keys [pos-x pos-y radius vel-x vel-y]} ball
bounce (fn [pos vel upper-bound]
(if (< radius pos (- upper-bound radius))
vel
(- vel)))
vel-x (bounce pos-x vel-x (.-width canvas))
vel-y (bounce pos-y vel-y (.-height canvas))]
{:pos-x (+ pos-x vel-x)
:pos-y (+ pos-y vel-y)
:radius radius
:vel-x vel-x
:vel-y vel-y}))
With the above, we can define our animate loop
(defn animate []
(.requestAnimationFrame js/window animate)
(let [updated-balls (swap! balls #(map update-ball %))]
(clear-canvas)
(run! draw-ball updated-balls)))
The key ideas are:
each entity (ball) is represented as a map
we have defined separate functions to draw and update the ball
everything is stored in a single atom
Some advantages:
the draw function is easy to test in isolation
the update function is easy to test at the REPL (arguably, it could be cleaned up further by passing in the canvas width and height, so that it is pure)
since all of the state is in a single atom, it is easy to reset! it with some new desired state (maybe to add new balls, or just for debugging purposes)
With the help of #Carcigenicate, this is a working script.
;;; Interact with canvas
(def canvas (.getElementById js/document "my-canvas"))
(def c (.getContext canvas "2d"))
;;; Set width and Height
(set! (.-width canvas) (.-innerWidth js/window))
(set! (.-height canvas) (.-innerHeight js/window))
(defrecord Ball [pos-x pos-y radius vel-x vel-y])
; Making the atom hold a list to hold multiple balls
(def balls-atom (atom []))
; You should prefer "->Ball" over the "Ball." constructor. The java interop form "Ball." has a few drawbacks
; And I'm adding to the balls vector. What you had before didn't make sense.
; You put an empty map in the atom, then immedietly overwrote it with a single ball
(doseq [ball (range 10)]
(swap! balls-atom conj (->Ball (+ 300 ball) (+ 100 ball) 20 (+ ball 1) (+ ball 1))))
; You called this create-ball, but it doesn't create anything. It draws a ball.
(defn draw-ball [ball]
; Deconstructing here for clarity
(let [{:keys [pos-x pos-y radius]} ball]
(.beginPath c)
(.arc c pos-x pos-y radius 0 (* 2 Math/PI))
(set! (.-lineWidth c) 5)
(set! (.-fillStyle c) "red")
(.fill c)
(.stroke c)))
(defn draw-balls [balls]
(doseq [ball balls]
(draw-ball ball)))
(defn out-of-boundaries
[ball]
"Check if ball is out of boundaries.
If it is, returns a new ball with inversed velocities."
(let [{:keys [pos-x pos-y vel-x vel-y radius]} ball]
;; This part was a huge mess. The calls to swap weren't even in the "if".
;; I'm using cond-> here. If the condition is true, it threads the ball. It works the same as ->, just conditionally.
(cond-> ball
(or (> (+ pos-x radius) (.-width canvas)) (< (- pos-x radius) 0))
(update :vel-x -) ; This negates the x velocity
(or (> (+ pos-y radius) (.-height canvas)) (< (- pos-y radius) 60))
(update :vel-y -)))) ; This negates the y velocity
; You're mutating atoms here, but that's very poor practice.
; This function should be pure and return the new ball
; I also got rid of the draw call here, since this function has nothing to do with drawing
; I moved the drawing to animate!.
(defn advance-ball [ball]
(let [{:keys [pos-x pos-y vel-x vel-y radius]} ball
; You had this appearing after the bounds check.
; I'd think that you'd want to move, then check the bounds.
moved-ball (-> ball
(update :pos-x + vel-x)
(update :pos-y + vel-y))]
(out-of-boundaries moved-ball)))
; For convenience. Not really necessary, but it helps things thread nicer using ->.
(defn advance-balls [balls]
(mapv advance-ball balls))
(defn animate
[]
(swap! balls-atom
(fn [balls]
(doto (advance-balls balls)
(draw-balls)))))
(animate)

gimp - creating layers 2d list

Hello I am trying to convert a bunch of layers ( drawables + masks ) into a 2d list for random access using list-ref. I have failed and I cant see where I am going wrong. The cmyk-list contains garbage. All drawables have been tested with this example template (gimp-invert magenta-layer-copy) before creating the list Your help, comments appreciated.
(set! layerList (cadr (gimp-image-get-layers image)))
(set! number-of-layers (vector-length layerList))
(set! cyan-layer-copy (aref layerList (- number-of-layers 4)))
(set! cyan-mask-copy (car (gimp-layer-get-mask cyan-layer-copy)))
(set! magenta-layer-copy (aref layerList (- number-of-layers 3)))
(set! magenta-mask-copy (car (gimp-layer-get-mask magenta-layer-copy)))
(set! yellow-layer-copy (aref layerList (- number-of-layers 2)))
(set! yellow-mask-copy (car (gimp-layer-get-mask yellow-layer-copy)))
(set! alpha-layer-copy (aref layerList (- number-of-layers 1)))
(set! cmyk-list '((cyan-layer-copy cyan-mask-copy)
(magenta-layer-copy magenta-mask-copy)
(yellow-layer-copy yellow-mask-copy)
(alpha-layer-copy 0)))

Operator Overloading in Racket / Scheme

I am having some trouble here, and hopefully you guys can help.
Basically, what I am trying to do is overload the + sign in racket so that it will add two vectors instead of two numbers. Also, I want to keep the old + operator so that we can still use it. I know this is supposed to work in scheme, so I was told I needed to use module* to do it in racket. I am still not entirely sure how it all works.
Here is what I have so far:
#lang racket
(module* fun scheme/base
(define old+ +)
(define + new+)
(define (new+ x y)
(cond ((and (vector? x) (vector? y))
(quatplus x y))
(else (old+ x y))))
(define (quatplus x y)
(let ((z (make-vector 4)))
(vector-set! z 0 (old+ (vector-ref x 0) (vector-ref y 0)))
(vector-set! z 1 (old+ (vector-ref x 1) (vector-ref y 1)))
(vector-set! z 2 (old+ (vector-ref x 2) (vector-ref y 2)))
(vector-set! z 3 (old+ (vector-ref x 3) (vector-ref y 3)))
z)))
But it doesn't seem to do anything at all. If anyone knows anything about this I would be very appreciative.
Thank you.
How I would do this is to use the except-in and rename-in specs for require:
#lang racket/base
(require (except-in racket + -)
(rename-in racket [+ old+] [- old-]))
(define (+ x y)
(cond [(and (vector? x) (vector? y))
(quatplus x y)]
[else (old+ x y)]))
(define (quatplus x y)
(vector (+ (vector-ref x 0) (vector-ref y 0))
(+ (vector-ref x 1) (vector-ref y 1))
(+ (vector-ref x 2) (vector-ref y 2))
(+ (vector-ref x 3) (vector-ref y 3))))
(+ (vector 1 2 3 4) (vector 1 2 3 4))
;; => #(2 4 6 8)
You could also use prefix-in with only-in, which would be more convenient if you had many such functions to rename:
(require (except-in racket + -)
(prefix-in old (only-in racket + -)))
A few points:
I had quatplus simply return a new immutable vector (instead of using make-vector and set!). It's simpler and probably faster.
Racket's + accepts any number of arguments. Maybe yours should?
As written, your new + will fail for the combination of a non-vector and a vector. You probably want to fix that:
(+ 1 (vector 1 2 3 4))
; +: contract violation
; expected: number?
; given: '#(1 2 3 4)
; argument position: 1st
; other arguments...:
; 1
You can use Scheme encapsulation to accomplish your needs as:
(import (rename (rnrs) (+ numeric+)))
(define +
(let ((vector+ (lambda (v1 v2) (vector-map numeric+ v1 v2)))
(list+ (lambda (l1 l2) (map numeric+ l1 l2)))
;; …
)
(lambda (a b)
(cond ((and (vector? a) (vector? b)) (vector+ a b))
((and (list? a) (list? b)) (list+ a b))
;; …
(else (numeric+ a b))))))
and if you wanted to work the addition to any depth, this should work:
(define +
(letrec ((vector+ (lambda (v1 v2) (vector-map any+ v1 v2)))
(list+ (lambda (l1 l2) (map any+ l1 l2)))
(any+ (lambda (a b)
(cond ((and (vector? a) (vector? b)) (vector+ a b))
((and (list? a) (list? b)) (list+ a b))
;; …
(else (numeric+ a b))))))
any+))
See:
> (+ (vector (list 1 2) 3) (vector (list 11 12) 13))
#((12 14) 16)

Lilypond: how to add the number of repetitions above a bar

I am working with a score in Lilypond that has a lot of repetitions, where basically every bar has to be repeated a certain number of times. I would like to be able to write above every bar the number of times it should be repeat, similar to the score below (which was not created in Lilypond):
It would be great to be able to have some brackets above the bar and also to have the "3x" centralized, just like in the example above. So far, the only (temporary) solution I was able to come up with in Lilypond was to add repeat bars and then simply write "3x" above the first note of every bar (since I could not have it centralized on the bar either). It does not look very good, but gets the job done. This temporary solution looks like this:
Any suggestions of how to make this example look more similar to the first inn Lilypond would be extremely welcome!
This is a workaround for this problem:
\version "2.19.15"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% COPY ALL THIS BELOW %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% repeatBracket snippet
% will add .----Nx----. above a bar, where N is the number of repetitions
% based on the wonderful spanner by David Nalesnik (see: http://lists.gnu.org/archive/html/lilypond-user/2014-10/msg00446.html )
#(define (test-stencil grob text)
(let* ((orig (ly:grob-original grob))
(siblings (ly:spanner-broken-into orig)) ; have we been split?
(refp (ly:grob-system grob))
(left-bound (ly:spanner-bound grob LEFT))
(right-bound (ly:spanner-bound grob RIGHT))
(elts-L (ly:grob-array->list (ly:grob-object left-bound 'elements)))
(elts-R (ly:grob-array->list (ly:grob-object right-bound 'elements)))
(break-alignment-L
(filter
(lambda (elt) (grob::has-interface elt 'break-alignment-interface))
elts-L))
(break-alignment-R
(filter
(lambda (elt) (grob::has-interface elt 'break-alignment-interface))
elts-R))
(break-alignment-L-ext (ly:grob-extent (car break-alignment-L) refp X))
(break-alignment-R-ext (ly:grob-extent (car break-alignment-R) refp X))
(num
(markup text))
(num
(if (or (null? siblings)
(eq? grob (car siblings)))
num
(make-parenthesize-markup num)))
(num (grob-interpret-markup grob num))
(num-stil-ext-X (ly:stencil-extent num X))
(num-stil-ext-Y (ly:stencil-extent num Y))
(num (ly:stencil-aligned-to num X CENTER))
(num
(ly:stencil-translate-axis
num
(+ (interval-length break-alignment-L-ext)
(* 0.5
(- (car break-alignment-R-ext)
(cdr break-alignment-L-ext))))
X))
(bracket-L
(markup
#:path
0.1 ; line-thickness
`((moveto 0.5 ,(* 0.5 (interval-length num-stil-ext-Y)))
(lineto ,(* 0.5
(- (car break-alignment-R-ext)
(cdr break-alignment-L-ext)
(interval-length num-stil-ext-X)))
,(* 0.5 (interval-length num-stil-ext-Y)))
(closepath)
(rlineto 0.0
,(if (or (null? siblings) (eq? grob (car siblings)))
-1.0 0.0)))))
(bracket-R
(markup
#:path
0.1
`((moveto ,(* 0.5
(- (car break-alignment-R-ext)
(cdr break-alignment-L-ext)
(interval-length num-stil-ext-X)))
,(* 0.5 (interval-length num-stil-ext-Y)))
(lineto 0.5
,(* 0.5 (interval-length num-stil-ext-Y)))
(closepath)
(rlineto 0.0
,(if (or (null? siblings) (eq? grob (last siblings)))
-1.0 0.0)))))
(bracket-L (grob-interpret-markup grob bracket-L))
(bracket-R (grob-interpret-markup grob bracket-R))
(num (ly:stencil-combine-at-edge num X LEFT bracket-L 0.4))
(num (ly:stencil-combine-at-edge num X RIGHT bracket-R 0.4)))
num))
#(define-public (Measure_attached_spanner_engraver context)
(let ((span '())
(finished '())
(event-start '())
(event-stop '()))
(make-engraver
(listeners ((measure-counter-event engraver event)
(if (= START (ly:event-property event 'span-direction))
(set! event-start event)
(set! event-stop event))))
((process-music trans)
(if (ly:stream-event? event-stop)
(if (null? span)
(ly:warning "You're trying to end a measure-attached spanner but you haven't started one.")
(begin (set! finished span)
(ly:engraver-announce-end-grob trans finished event-start)
(set! span '())
(set! event-stop '()))))
(if (ly:stream-event? event-start)
(begin (set! span (ly:engraver-make-grob trans 'MeasureCounter event-start))
(set! event-start '()))))
((stop-translation-timestep trans)
(if (and (ly:spanner? span)
(null? (ly:spanner-bound span LEFT))
(moment<=? (ly:context-property context 'measurePosition) ZERO-MOMENT))
(ly:spanner-set-bound! span LEFT
(ly:context-property context 'currentCommandColumn)))
(if (and (ly:spanner? finished)
(moment<=? (ly:context-property context 'measurePosition) ZERO-MOMENT))
(begin
(if (null? (ly:spanner-bound finished RIGHT))
(ly:spanner-set-bound! finished RIGHT
(ly:context-property context 'currentCommandColumn)))
(set! finished '())
(set! event-start '())
(set! event-stop '()))))
((finalize trans)
(if (ly:spanner? finished)
(begin
(if (null? (ly:spanner-bound finished RIGHT))
(set! (ly:spanner-bound finished RIGHT)
(ly:context-property context 'currentCommandColumn)))
(set! finished '())))
(if (ly:spanner? span)
(begin
(ly:warning "I think there's a dangling measure-attached spanner :-(")
(ly:grob-suicide! span)
(set! span '())))))))
\layout {
\context {
\Staff
\consists #Measure_attached_spanner_engraver
\override MeasureCounter.font-encoding = #'latin1
\override MeasureCounter.font-size = 0
\override MeasureCounter.outside-staff-padding = 2
\override MeasureCounter.outside-staff-horizontal-padding = #0
}
}
repeatBracket = #(define-music-function
(parser location N note)
(number? ly:music?)
#{
\override Staff.MeasureCounter.stencil =
#(lambda (grob) (test-stencil grob #{ #(string-append(number->string N) "×") #} ))
\startMeasureCount
\repeat volta #N { $note }
\stopMeasureCount
#}
)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ...UNTIL HERE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{
\repeatBracket 7 {c'1}
\repeatBracket 32 {d' g}
\repeatBracket 14 {e' f g}
\repeatBracket 29 {f' a bes \break cis' e''}
\repeatBracket 1048 {g'1}
}
This code above gives the following result:
]
This solution was not created by myself, but sent to me by David Nalesnik, from lilypond-user mailing list. I just would like to share it here in case someone would need it as well. I've made just some very minor adjustments to what David sent me.
I just had a similar problem but preferred the style on your second example, with the 3x above the bar. The solution I found was:
f e d c |
\mark \markup {"3x"}\repeat volta 3 {c d e f}
f e d c |
generating
Maybe someone else has a use for it.