Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ mscz/
*.db

*.zip
dist/
dist/

# audio
*.mp3
*.mid
*.midi
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,6 @@ Development pauses occasionally when I research better automation approaches
- https://www.musicca.com/dictionary/scales
- https://www.gkiharapanindah.org/download/rekap-kidung-jemaat/
- https://mymusictheory.com/more-music-theory-topics/key-signatures-chart/
- https://fontdrop.info/#/?darkmode=true
- https://fontdrop.info/#/?darkmode=true
- Original MIDI Audio Arrangement by GEMA/SABDA (sabda.org). Modified for single-verse playback.
- Sound Effect by <a href="https://pixabay.com/users/freesound_community-46691455/?utm_source=link-attribution&utm_medium=referral&utm_campaign=music&utm_content=91643">freesound_community</a> from <a href="https://pixabay.com//?utm_source=link-attribution&utm_medium=referral&utm_campaign=music&utm_content=91643">Pixabay</a>
174 changes: 174 additions & 0 deletions cmd/lab/audio-stream/stream/audio_stream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package stream

import (
"io"
"log"
"net/http"
"os"
"strconv"
"sync"
"time"

"github.com/hcl/audioduration"
"github.com/julienschmidt/httprouter"
)

type AudioStream struct {
Sig chan os.Signal
}

func (dh *AudioStream) ServeHTTP(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

paths := []string{
`/home/jodiivan/go/src/github.com/jodi-ivan/numbered-notation-xml/files/audio/kj-001-opening.mp3`,
`/home/jodiivan/go/src/github.com/jodi-ivan/numbered-notation-xml/files/audio/kj-001-core.mp3`,
}

openingFile, err := os.Open(paths[0])
if err != nil {
log.Println("Failed to open openingFile", err.Error())
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}

defer openingFile.Close()

openingDuration, err := audioduration.Mp3(openingFile)
if err != nil {
log.Println("Failed to calculate mp3 opening duration", err.Error())
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}

coreFile, err := os.Open(paths[1])
if err != nil {
log.Println("Failed to open coreFile", err.Error())
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}

defer coreFile.Close()

repeatRaw := r.FormValue("repeat")

repeat, err := strconv.Atoi(repeatRaw)
if repeatRaw != "" && err != nil {
log.Printf("[ServeHTTP] invalid verse: %v", err.Error())
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid URL"))
return
}

if repeat == 1 {
repeat = 0
}

w.Header().Set("Connection", "Keep-Alive")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("Transfer-Encoding", "chunked")
w.Header().Set("Content-Type", "audio/mpeg")

ctx := r.Context()
currRepeat := 1
measure := 0
measureMtx := sync.Mutex{}

songMeasure := 23.0
songTempo := 85.0
songDuration := ((songMeasure * 4) / songTempo) * 60.0
op := time.Duration(openingDuration * float64(time.Second))
core := time.Duration(songDuration * float64(time.Second)) // for 1 timesignature no changes
log.Println("wait for ", op.String())

files := []*os.File{
openingFile,
coreFile,
}
go func() {

<-time.After(op)
measure = 1
log.Println("Start: Measure ", measure)
ticker := time.NewTicker(core / 23)
defer ticker.Stop()

for {
select {
case <-ticker.C:
measureMtx.Lock()
measure++
measureMtx.Unlock()
log.Println("Measure ", measure)
if measure == 23 {
return
}
case <-dh.Sig:
log.Println("os signal interrupt")
return
}
}

}()

for i, file := range files {

buf := make([]byte, 4096) // 4KB chunks

// Loop core indefinitely
for {
select {
case <-ctx.Done():
log.Println("context timeout")

return
case <-dh.Sig:
log.Println("os signal interrupt")
return
default:
}

n, err := file.Read(buf)
if err != nil {
if err == io.EOF {
log.Println("Music ", file.Name(), " is finished")
// if i == 1 && currRepeat == repeat {
// break
// }
measureMtx.Lock()
measure = 0
measureMtx.Unlock()

if i == 0 || ((i == 1 && repeat == 0) || (i == 1 && currRepeat == repeat)) {
break
} else if currRepeat < repeat {
currRepeat++
file.Seek(0, 0)
continue
}
}
log.Println("Failed to ", err.Error())
return
}

_, werr := w.Write(buf[:n])
if werr != nil {
log.Println("Failed to ", werr.Error())
return
}

if f, ok := w.(http.Flusher); ok {
f.Flush()
}

}
}

// wg.Wait()

log.Println("It is done")

}
7 changes: 6 additions & 1 deletion cmd/rest/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"syscall"

"github.com/jodi-ivan/numbered-notation-xml/adapter"
strmadapter "github.com/jodi-ivan/numbered-notation-xml/cmd/lab/audio-stream/stream"
lab "github.com/jodi-ivan/numbered-notation-xml/cmd/rest/adapter"
"github.com/jodi-ivan/numbered-notation-xml/decorator"
"github.com/jodi-ivan/numbered-notation-xml/internal/renderer"
Expand Down Expand Up @@ -63,14 +64,18 @@ func main() {
Db: db,
})

sigs := make(chan os.Signal, 1)
sigs := make(chan os.Signal, 2)

ws.Register("GET", "/internal/diagnostic/verse/:scope", &adapter.DiagnosticHTTP{
Usecase: usecaseMod,
Interrupt: sigs,
Repo: repo,
})

ws.Register("GET", "/internal/v1/lab", &strmadapter.AudioStream{
Sig: sigs,
})

err = ws.Serve(cfg.Webserver.Port)
if err != nil {
log.Printf("Failed to start the server. Err: %s", err.Error())
Expand Down
1 change: 1 addition & 0 deletions files/audio/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
put your *.mp3 file
Loading