Audio files download on application start. Home screen shows status message

This commit is contained in:
NeilClack
2026-06-18 21:52:29 -05:00
parent 7ecb90b63b
commit 2af1aae885
5 changed files with 146 additions and 76 deletions
+27 -5
View File
@@ -12,6 +12,7 @@ import (
"github.com/veandco/go-sdl2/ttf"
"gorm.io/gorm"
"rhemawavetech.com/rhemawave/internal/db"
"rhemawavetech.com/rhemawave/internal/download"
"rhemawavetech.com/rhemawave/internal/fontManager"
"rhemawavetech.com/rhemawave/internal/graphics"
"rhemawavetech.com/rhemawave/internal/keybinds"
@@ -153,18 +154,39 @@ func Run() {
app.initializeManagers()
app.initializeAudio()
downloadProgressChan := make(chan download.DownloadStatus)
app.PageRouter = page.NewRouter(page.PageCtx{
CfgPtr: app.Config.Load(),
DbPtr: app.DB,
W: w,
H: h,
RefreshConfig: app.refreshCache,
CfgPtr: app.Config.Load(),
DbPtr: app.DB,
W: w,
H: h,
MessageChannel: downloadProgressChan,
RefreshConfig: app.refreshCache,
})
// Sync the proclamations from the API to the Database
sync.SyncProclamations(DB)
sync.SyncCategories(DB)
sync.SyncFrequencies(DB)
audioFileNames := []string{
"OriginalAudio.wav",
"174Hz.wav",
"396Hz.wav",
"417Hz.wav",
"432Hz.wav",
"639Hz.wav",
"741Hz.wav",
"852Hz.wav",
"963Hz.wav",
"1111Hz.wav",
"14Hz_Binaural.wav",
"40Hz_Binaural.wav",
"AlphaWaves.wav",
"PinealGland.wav",
}
go download.DownloadAudioFiles(app.PageRouter.Context.MessageChannel, audioFileNames, filepath.Join(app.PageRouter.Context.CfgPtr.AssetsDir, "audio"))
app.runEventLoop()
}
+1 -1
View File
@@ -162,7 +162,7 @@ func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string,
progressChan <- DownloadStatus{
Max: totalSize,
Cur: totalDownloaded,
Msg: fmt.Sprintf("Finished downloading %s", filename),
Msg: "Finished Downloading",
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ func Init(cfg *db.AppConfig, onUpdate func()) error {
return err
}
SetAllSinkVolumes(1.0)
SetAllSinkVolumes(0.3)
inited = true
return nil
+108 -62
View File
@@ -2,8 +2,6 @@ package page
import (
"fmt"
"path/filepath"
"time"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/mathgl/mgl32"
@@ -30,8 +28,8 @@ type Home struct {
emailDisplay StringItem
licenseKeyDisplay StringItem
hasLicenseInfo bool
lastDisplayUpdate time.Time
baseFontSize int // cached from db at init
baseFontSize int
isDownloadComplete bool
}
// Init performs basic page initialization and creation of static assets.
@@ -82,6 +80,12 @@ func (p *Home) Init(ctx *PageCtx) error {
// Create download channel and message
p.downloadProgressChan = make(chan download.DownloadStatus)
// Initialize message
p.message, err = NewStringItem("Status: Initializing...", font, colors.White)
if err != nil {
return fmt.Errorf("unable to create initial message texture: %w", err)
}
// Create license info textures if data exists
if p.Context.CfgPtr.EmailAddress != "" || p.Context.CfgPtr.LicenseKey != "" {
p.hasLicenseInfo = true
@@ -113,44 +117,33 @@ func (p *Home) Init(ctx *PageCtx) error {
// Get base font size from database
baseFontSize := p.Context.CfgPtr.StandardFontSize
p.baseFontSize = baseFontSize
// Scale the note text
fontSize := int32(32)
scale := float32(fontSize) / float32(baseFontSize)
p.note.Scale(scale * 0.75)
p.note.W = int32(float32(p.note.W) * scale * 0.75)
p.note.H = int32(float32(p.note.H) * scale * 0.75)
// Scale license info texts
if p.hasLicenseInfo {
licenseInfoScale := float32(28) / float32(baseFontSize)
p.licenseInfoHeading.Scale(licenseInfoScale)
p.licenseInfoHeading.W = int32(float32(p.licenseInfoHeading.W) * licenseInfoScale)
p.licenseInfoHeading.H = int32(float32(p.licenseInfoHeading.H) * licenseInfoScale)
if p.emailDisplay.ID != 0 {
p.emailDisplay.Scale(licenseInfoScale * 0.85)
p.emailDisplay.W = int32(float32(p.emailDisplay.W) * licenseInfoScale * 0.85)
p.emailDisplay.H = int32(float32(p.emailDisplay.H) * licenseInfoScale * 0.85)
}
if p.licenseKeyDisplay.ID != 0 {
p.licenseKeyDisplay.Scale(licenseInfoScale * 0.85)
p.licenseKeyDisplay.W = int32(float32(p.licenseKeyDisplay.W) * licenseInfoScale * 0.85)
p.licenseKeyDisplay.H = int32(float32(p.licenseKeyDisplay.H) * licenseInfoScale * 0.85)
}
}
audioFileNames := []string{
"OriginalAudio.wav",
"174Hz.wav",
"396Hz.wav",
"417Hz.wav",
"432Hz.wav",
"639Hz.wav",
"741Hz.wav",
"852Hz.wav",
"963Hz.wav",
"1111Hz.wav",
"14Hz_Binaural.wav",
"40Hz_Binaural.wav",
"AlphaWaves.wav",
"PinealGland.wav",
}
go download.DownloadAudioFiles(p.downloadProgressChan, audioFileNames, filepath.Join(ctx.CfgPtr.AssetsDir, "audio"))
// Scale message text
messageScale := float32(28) / float32(baseFontSize)
p.message.W = int32(float32(p.message.W) * messageScale)
p.message.H = int32(float32(p.message.H) * messageScale)
return nil
}
@@ -162,20 +155,44 @@ func (p *Home) HandleEvent(event *sdl.Event) error {
// Update updates animations and changing textures and other changes using `dt` which represents a time delta in float32.
func (p *Home) Update(dt float32) error {
var err error
select {
case progressUpdate := <-p.downloadProgressChan:
if progressUpdate.Err != nil {
p.message, err = NewStringItem(progressUpdate.Msg, p.font, colors.White)
case progressUpdate, ok := <-p.Context.MessageChannel:
if !ok {
// Channel is closed, set message to READY
newMsg, err := NewStringItem("Status: READY", p.font, colors.Green)
if err != nil {
return err
}
messageScale := float32(28) / float32(p.baseFontSize)
newMsg.W = int32(float32(newMsg.W) * messageScale)
newMsg.H = int32(float32(newMsg.H) * messageScale)
p.message = newMsg
p.isDownloadComplete = true
} else if progressUpdate.Err != nil {
// Handle error
newMsg, err := NewStringItem(fmt.Sprintf("Status: %s", progressUpdate.Err.Error), p.font, colors.Red)
if err != nil {
return err
}
messageScale := float32(28) / float32(p.baseFontSize)
newMsg.W = int32(float32(newMsg.W) * messageScale)
newMsg.H = int32(float32(newMsg.H) * messageScale)
p.message = newMsg
} else {
p.message, err = NewStringItem(progressUpdate.Err.Error(), p.font, colors.Red)
// Update progress message
percentComplete := float64(progressUpdate.Cur) / float64(progressUpdate.Max) * 100
msg := fmt.Sprintf("Status: Downloading assets %.1f%% Complete", percentComplete)
newMsg, err := NewStringItem(msg, p.font, colors.White)
if err != nil {
return err
}
messageScale := float32(28) / float32(p.baseFontSize)
newMsg.W = int32(float32(newMsg.W) * messageScale)
newMsg.H = int32(float32(newMsg.H) * messageScale)
p.message = newMsg
}
default:
return nil
// No update, do nothing
}
return nil
}
@@ -184,6 +201,7 @@ func (p *Home) Render() error {
baseFontSize := p.baseFontSize
sm := shaderManager.Get()
verticalMargin := int32(20)
licenseInfoMargin := int32(10)
// 1) Calculate scales
titleFontSize := int32(64)
@@ -205,9 +223,26 @@ func (p *Home) Render() error {
promptH := float32(p.prompt.H) * bodyScale
promptDim := mgl32.Vec2{promptW, promptH}
// p.note already scaled in Init via p.note.Scale(scale*0.75)
noteDim := p.note.RawDimensions()
noteW, noteH := noteDim[0], noteDim[1]
// Note dimensions (already scaled in Init)
noteW := float32(p.note.W)
noteH := float32(p.note.H)
// Message dimensions (already scaled in Init/Update)
messageW := float32(p.message.W)
messageH := float32(p.message.H)
// License info dimensions (already scaled in Init)
licenseHeadingW := float32(p.licenseInfoHeading.W)
licenseHeadingH := float32(p.licenseInfoHeading.H)
var emailDisplayW, emailDisplayH, licenseKeyDisplayW, licenseKeyDisplayH float32
if p.emailDisplay.ID != 0 {
emailDisplayW = float32(p.emailDisplay.W)
emailDisplayH = float32(p.emailDisplay.H)
}
if p.licenseKeyDisplay.ID != 0 {
licenseKeyDisplayW = float32(p.licenseKeyDisplay.W)
licenseKeyDisplayH = float32(p.licenseKeyDisplay.H)
}
// 3) Calculate total height of the vertical stack
totalH := int32(titleH) + verticalMargin +
@@ -218,7 +253,7 @@ func (p *Home) Render() error {
// 4) Y-up layout: start from the TOP of the centered stack and step DOWN
top := p.Base.ScreenCenterY + totalH/2
titleY := top - int32(titleH) // Title sits at the top
titleY := top - int32(titleH)
versionY := titleY - verticalMargin - int32(versionH)
p.prompt.Y = versionY - verticalMargin - int32(promptH)
p.note.Y = p.prompt.Y - verticalMargin - int32(noteH)
@@ -234,23 +269,8 @@ func (p *Home) Render() error {
// 6) Position license info at bottom center
if p.hasLicenseInfo {
licenseInfoMargin := int32(10)
bottomMargin := int32(20)
// License info items are already scaled in Init
licenseHeadingDim := p.licenseInfoHeading.RawDimensions()
licenseHeadingW, licenseHeadingH := licenseHeadingDim[0], licenseHeadingDim[1]
var emailDisplayH, licenseKeyDisplayH float32
if p.emailDisplay.ID != 0 {
emailDisplayDim := p.emailDisplay.RawDimensions()
emailDisplayH = emailDisplayDim[1]
}
if p.licenseKeyDisplay.ID != 0 {
licenseKeyDisplayDim := p.licenseKeyDisplay.RawDimensions()
licenseKeyDisplayH = licenseKeyDisplayDim[1]
}
// Calculate total height of license info block
licenseInfoTotalH := int32(licenseHeadingH)
if p.emailDisplay.ID != 0 {
@@ -265,8 +285,6 @@ func (p *Home) Render() error {
// License key (bottom-most if it exists)
if p.licenseKeyDisplay.ID != 0 {
licenseKeyDisplayDim := p.licenseKeyDisplay.RawDimensions()
licenseKeyDisplayW := licenseKeyDisplayDim[0]
p.licenseKeyDisplay.X = p.Base.ScreenCenterX - int32(licenseKeyDisplayW/2)
p.licenseKeyDisplay.Y = currentY
currentY += int32(licenseKeyDisplayH) + licenseInfoMargin
@@ -274,8 +292,6 @@ func (p *Home) Render() error {
// Email
if p.emailDisplay.ID != 0 {
emailDisplayDim := p.emailDisplay.RawDimensions()
emailDisplayW := emailDisplayDim[0]
p.emailDisplay.X = p.Base.ScreenCenterX - int32(emailDisplayW/2)
p.emailDisplay.Y = currentY
currentY += int32(emailDisplayH) + licenseInfoMargin
@@ -286,6 +302,26 @@ func (p *Home) Render() error {
p.licenseInfoHeading.Y = currentY
}
// 7) Position message between license info and note/prompt
if p.hasLicenseInfo {
// Calculate the top of the license info block
licenseInfoTopY := p.licenseInfoHeading.Y + int32(licenseHeadingH)
if p.emailDisplay.ID != 0 {
licenseInfoTopY += int32(emailDisplayH) + licenseInfoMargin
}
if p.licenseKeyDisplay.ID != 0 {
licenseInfoTopY += int32(licenseKeyDisplayH) + licenseInfoMargin
}
// Center the message vertically between license info and note
availableSpace := p.note.Y - licenseInfoTopY - verticalMargin
p.message.Y = licenseInfoTopY + availableSpace/2 - int32(messageH/2)
} else {
// If no license info, place message below note
p.message.Y = p.note.Y - verticalMargin - int32(messageH)
}
p.message.X = p.Base.ScreenCenterX - int32(messageW/2)
// 8) Get shader and render
textShader, ok := sm.Get("text")
if !ok {
@@ -295,17 +331,26 @@ func (p *Home) Render() error {
p.Base.RenderTexture(textShader, p.title.ID, titlePos, titleDim, color)
p.Base.RenderTexture(textShader, p.version.ID, versionPos, versionDim, color)
p.Base.RenderTexture(textShader, p.prompt.ID, p.prompt.Position(), promptDim, color)
p.Base.RenderTexture(textShader, p.note.ID, p.note.Position(), p.note.RawDimensions(), color)
p.Base.RenderTexture(textShader, p.prompt.ID, mgl32.Vec2{float32(p.prompt.X), float32(p.prompt.Y)}, promptDim, color)
p.Base.RenderTexture(textShader, p.note.ID, mgl32.Vec2{float32(p.note.X), float32(p.note.Y)}, mgl32.Vec2{noteW, noteH}, color)
// Render message
if p.message.ID != 0 {
msgColor := colors.White
if p.isDownloadComplete {
msgColor = colors.Green
}
p.Base.RenderTexture(textShader, p.message.ID, mgl32.Vec2{float32(p.message.X), float32(p.message.Y)}, mgl32.Vec2{messageW, messageH}, msgColor)
}
// Render license info if it exists
if p.hasLicenseInfo {
p.Base.RenderTexture(textShader, p.licenseInfoHeading.ID, p.licenseInfoHeading.Position(), p.licenseInfoHeading.RawDimensions(), color)
p.Base.RenderTexture(textShader, p.licenseInfoHeading.ID, mgl32.Vec2{float32(p.licenseInfoHeading.X), float32(p.licenseInfoHeading.Y)}, mgl32.Vec2{licenseHeadingW, licenseHeadingH}, color)
if p.emailDisplay.ID != 0 {
p.Base.RenderTexture(textShader, p.emailDisplay.ID, p.emailDisplay.Position(), p.emailDisplay.RawDimensions(), color)
p.Base.RenderTexture(textShader, p.emailDisplay.ID, mgl32.Vec2{float32(p.emailDisplay.X), float32(p.emailDisplay.Y)}, mgl32.Vec2{emailDisplayW, emailDisplayH}, color)
}
if p.licenseKeyDisplay.ID != 0 {
p.Base.RenderTexture(textShader, p.licenseKeyDisplay.ID, p.licenseKeyDisplay.Position(), p.licenseKeyDisplay.RawDimensions(), color)
p.Base.RenderTexture(textShader, p.licenseKeyDisplay.ID, mgl32.Vec2{float32(p.licenseKeyDisplay.X), float32(p.licenseKeyDisplay.Y)}, mgl32.Vec2{licenseKeyDisplayW, licenseKeyDisplayH}, color)
}
}
@@ -318,6 +363,7 @@ func (p *Home) Destroy() error {
gl.DeleteTextures(1, &p.version.ID)
gl.DeleteTextures(1, &p.prompt.ID)
gl.DeleteTextures(1, &p.note.ID)
gl.DeleteTextures(1, &p.message.ID)
if p.hasLicenseInfo {
gl.DeleteTextures(1, &p.licenseInfoHeading.ID)
+9 -7
View File
@@ -3,6 +3,7 @@ package page
import (
"gorm.io/gorm"
"rhemawavetech.com/rhemawave/internal/db"
"rhemawavetech.com/rhemawave/internal/download"
)
type pageType int
@@ -22,13 +23,14 @@ const (
)
type PageCtx struct {
CfgPtr *db.AppConfig
DbPtr *gorm.DB
W, H int32
RefreshConfig func()
NavigateTo func(pageType)
Msg string // Message to be displayed by MessagePage
Inst string // Instructions to be displayed on MessagePage
CfgPtr *db.AppConfig
DbPtr *gorm.DB
W, H int32
MessageChannel chan download.DownloadStatus
RefreshConfig func()
NavigateTo func(pageType)
Msg string // Message to be displayed by MessagePage
Inst string // Instructions to be displayed on MessagePage
}
type Router struct {