commit 38050e5c69c534b2cd3d3be0e5e0b5a907efc210 Author: Mindboost <> Date: Tue Jul 1 10:53:26 2025 +0000 Initial commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5cb376d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +**/.classpath +**/.dockerignore + +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..971b906 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,27 @@ +module.exports = { + root: true, + extends: [ + '@nuxtjs/eslint-config', + '@nuxtjs/eslint-config-typescript', + 'plugin:jsonc/recommended-with-jsonc' + ], + ignorePatterns: [ + 'assets/', + '**/*.svg', + '**/*.png', + '**/*.md', + 'i', + 'cert/', + 'android', + 'ios', + 'Dockerfile*', + '*.dev', + '*.ts' + ], + rules: { + 'vue/singleline-html-element-content-newline': 'off', + 'vue/singleline-html-element-content-whitespace': 'off', + 'vue/no-v-html': 'error', // Verhindert unsicheres HTML + '@typescript-eslint/no-unused-vars': 0 + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7045684 --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# Dependency directories +node_modules/ +yarn.lock + +# Nuxt build output +.nuxt +.nuxt/ +dist/ +.nuxt-build/ +.output/ +.env + +# Our Noise +!public/masking/fullband.wav + +# Capacitor build files +android/ +ios/ + +# Production build files +build/ +*.tar +*.tar.gz + +# Dotfiles and directories +.env.* +!.env.example +.DS_Store +.gitattributes +**/.DS_Store + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +logs/ + +# Local development +local/ +yarn.lock + +# Audio files +*.wav + +* text=auto diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..c483022 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..f34407b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..52fbc18 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Nuxt 3: Chrome starten auf HTTPS", + "url": "https://localhost:3000", + "webRoot": "${workspaceFolder}", + "runtimeArgs": [ + "--ignore-certificate-errors" + ] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..461c527 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,29 @@ +{ +<<<<<<< HEAD + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "eslint.validate": ["typescript", "javascript", "vue", "json"], +} +======= + "terminal.integrated.env.osx": { + "PATH": "" + }, + "terminal.integrated.env.linux": { + "PATH": "" + }, + "terminal.integrated.env.windows": { + "PATH": "" + }, + "terminal.integrated.defaultProfile.osx": "bash", + "terminal.integrated.profiles.osx": { + "bash": { + "path": "bash", + "args": [ + "-l" + ] + } + }, + "nodejs.runtime": "/usr/local/bin/node" +} +>>>>>>> simple_visualisation diff --git a/DESCRIPTION.md b/DESCRIPTION.md new file mode 100644 index 0000000..257ba9f --- /dev/null +++ b/DESCRIPTION.md @@ -0,0 +1,57 @@ +# Architecture + +This project is the frontend implementation of Mindboosts Web Application. It is a Vue 3 Nuxt 3 application running on an node server without serverside rendering. + +It consists basically of an login and registration functionality, an onboarding to get relevant information like the input device and personal preferences, an settings menu, four index pages that contain the RNBO player which is needed to use the patented algorithm and the place of all audio output. + +**login & regsistration** +This branches are used to experiment for your own on a specific task but always have a personal backup +Path Styling: `/yourname/task-or-feature-name` + +**onboarding** +This branches are used to add team wide tooling features like eslint for better coding experience +Path Styling `/tooling/tool-beeing-applied` + +**settings menu** +This branches are used to develop features for the app +Path Styling `/feature/name-of-the-branch` + +**index pages** +This branches are used to develop features for the app +Path Styling `/feature/name-of-the-branch` + +**RNBO Player** +The RNBO player is a vue component that provides the audio output via the WebAudio-API of the application. It loads two RNBO devices (`music device`, `noise device`), each has its own `patch.export.json` (exported from RNBO-Application). The devices will be loaded as `Audio Nodes` so that we can connect other nodes of the same Audio Context. The `music device` has three inputs: on channel 0 we attach an `MediaStreamSourceNode` which is a direct stream of the users choosed microphone, on channel 1 we attach the left channel of an `ChannelSplitterNode`, on channel 2 we attach the right channel of the `ChannelSplitterNode`. The two output channels of the `music device` are attached to the `noise device` the second RNBO device and to the music-`GainNode`. The `noise device` has five input channels: on channel 0 we attach the same `MediaStreamSourceNode` we use for the `music device` and on channel 1 we attach the left channel of a `ChannelSplitterNode` and on channel 2 we attach the right channel. This `ChannelSplitterNode` gets two input channels from an `BufferAudioSourceNode` which is a buffer containing the masking noise. The masking noise is fetched from the resources provided in the public folder of the node server. Channel 3 of our `noise device` is the left output of the `music device` passed though another `ChannelSplitterNode` and the right output on channel 4. +The output of our `noise device` is attached to the noise-`GainNode`. The two gain nodes (music-`GainNode` and noise-`GainNode`) are connected with the destination of the AudioContext. The destination is the user selected audio output, you should hear the music and the noise. The GainNodes gain value can be managed via the UI-sliders of the RNBOPlayer component. + +**Use of Web Audio API** +The following pages or components make use of Web Audio +* AcusticCheck.vue : For analysing purposes. +* RNBOPlayer.vue : To create the RNBO Devices and attached them to the right sources and destionations as descriped in RNBOPlayer above +* homeforest.vue : Require access to the Microphone for updating the vue meter that shows an simple dynamic bar chart of the users microphone input +* homemeadow.vue : : Require access to the Microphone for updating the vue meter... +* hometropics.vue : Require access to the Microphone for updating the vue meter... +* index.vue : Require access to the Microphone for updating the vue meter... +* onboarding.vue : Require access to the Microphone for updating the vue meter... + +**Path Management** +In this project, some files are linked to our algorithm. To modify the paths it is possible to change for example the source of the audio files via the .env-file. + +**AudioStore** +One problem we faceing within the application is due to the current achitecture every time we change the page +the old page is unmounted and with it the AudioContext. As the AudioContext need to be unlocked via user interaction it requires always an user input before we can use the WebAudio API. To avoid this behaviour we decided to have a shared audio context, that only needed to be unlocked once. So that we could make use of it in home pages of our soundscapes like e.g. `homeforest.vue` and within the `RNBOPlayer.vue` +We use an pinia store for it. The audiostore provides different functionality for the whole application as long as it is imported correctly. +It has a shared state... +* audioContext : The audio context we create within the action `initializeAudioContext()` by the use of Howler.js. Implemeented with Howler.js what comes along with the functionalities for automatically unlock the AudioContext. +* microphone : An object of class `Microphone` defined aswell in audio.ts. Its a wrapper for the microphoneStream an instance of `MediaStream` and microphoneNode an instance of `MediaStreamSourceNode`. The nodes are used to access the microphone, our `microphoneNode` are connected to the RNBO device and the MediaStream is used for updating the vue meter. +* nodes : An array of `AudioNodeItem` objects. `AudioNodeItem` are wrappers to track that type and state of available `AudioNode`-objects in our application. +* headsetType : The type of the headset the user selected. This is important to calculate the correct attention factor in RNBODevice +* ancDevice : The users selection if it has an headset with active noise cancelling (ANC) functionality. This is used to calculate the correct attention factor +* connectedSoundScape : This is the soundscape selected by the user. +* playing : This is the shared state if currently the audio is playing or not. This is used by UI elements in homebar, the bottombar and the RNBOPlayer to display the correct play / pause button +* acusticCheckResult : This is the calculated result of the current acustic check result, but is not used so far +* audioFiles : This is a array of AudioBuffers when loaded into the memory. After fetching the audio sources from the node server the audio files are saved in the indexed db. If a buffer is loaded from the indexeddb or direct from the axios response it will be saved in the audioFiles. This makes it easy to create new 'AudioNode'-like objects from preloaded buffers. This is the most important to avoid long loading time and delays. +* loadingBuffers : This is a store internal state representing that currently one or more buffers being fetched or processed + +...and shared actions +* to be done diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3ddcf9c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM node:18.19.1 as builder + + +WORKDIR /app +ARG BACKEND_URL +ENV BACKEND_URL ${BACKEND_URL} + +ENV NODE_OPTIONS=--openssl-legacy-provider +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +FROM node:18-slim as run + +WORKDIR /app +ARG BACKEND_URL +ENV BACKEND_URL ${BACKEND_URL} +COPY package*.json ./ +COPY --from=builder /app/.output .output +RUN ls -la /app + +EXPOSE 3000 + +CMD [ "node", ".output/server/index.mjs"] diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..c7d9bc9 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,20 @@ +FROM node:18.14.2 + +WORKDIR /app + +ENV NODE_OPTIONS=--openssl-legacy-provider + +# Installiere Abhängigkeiten +COPY package*.json ./ +RUN npm install + +# Kopiere restliche Dateien und baue das Projekt +COPY . . +RUN npm run build +ENV PATH /app/node_modules/.bin:$PATH + +# Exponiere den Port für den Entwicklungsserver +EXPOSE 3000 + +# Starte den Entwicklungsserver, wenn der Container ausgeführt wird +CMD ["npm", "run", "dev"] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..2e3ed94 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,70 @@ +pipeline { + agent any + + stages { + stage('Checkout') { + steps { + script { + checkout([ + $class: 'GitSCM', + branches: [[name: 'pipeline/deploy-image']], + userRemoteConfigs: [[ + url: 'https://gitea.mindboost.team/Mindboost/mindboost-webapp.git', + credentialsId: 'b5f383be-8c74-40f9-b7e1-3a9c5856df0e' + ]] + ]) + } + } + } + + stage('Check Repository') { + steps { + script { + sh 'pwd' // Zeigt das aktuelle Verzeichnis + sh 'ls -la' // Prüft, ob das .git-Verzeichnis existiert + sh 'git status' // Stellt sicher, dass das Repo korrekt initialisiert ist + } + } + } + + stage('Get Commit Hash') { + steps { + script { + env.WEBAPP_COMMIT_HASH = sh( + script: 'git rev-parse --short HEAD', + returnStdout: true + ).trim() + echo "Commit Hash: ${env.WEBAPP_COMMIT_HASH}" + } + } + } + stage('Check Docker Image with the same tag') { + steps { + script { + def imageExists = sh( + script: "docker images -q mindboost_frontend_image:${env.WEBAPP_COMMIT_HASH} || true", + returnStdout: true + ).trim() + + if (imageExists) { + echo "Docker Image mit Tag ${env.WEBAPP_COMMIT_HASH} existiert bereits. Überspringe Build." + currentBuild.result = 'SUCCESS' + return + } else { + echo "Kein vorhandenes Docker Image gefunden. Baue neues Image..." + } + } + } + } + stage('Build Docker Image') { + when { + expression { currentBuild.result == null } // Nur wenn vorher kein Image existierte + } + steps { + script { + sh "docker build --build-arg BACKEND_URL=https://b.mindboost.team --rm -t mindboost_frontend_image:${env.WEBAPP_COMMIT_HASH} . " + } + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb49eb0 --- /dev/null +++ b/README.md @@ -0,0 +1,150 @@ +# Contribution + +If you want to contribute, pull the branch `dev` and create a new branch from it. You are free to push the branch up to have a personal backup from your contributions. + +we recommed three types of branches: + +**Personal Branch** +This branches are used to experiment for your own on a specific task but always have a personal backup +Path Styling: `/yourname/task-or-feature-name` + +**Tooling branches** +This branches are used to add team wide tooling features like eslint for better coding experience +Path Styling `/tooling/tool-beeing-applied` + +**Feature branches** +This branches are used to develop features for the app +Path Styling `/feature/name-of-the-branch` + +## Merging branches +The recommended way to merge is a pull request on the `dev` branch. This requires that eslint is free of issues and the application compiles successfully + +Please commit all your changes in that branch and merge it (after another pull) into `dev` and push it. So everybody is up to date and we have no issues integrating different versions. + +# Logging + +This project used pino for logging on client and server side. Currently only client side is tested. + +## How to use: +In pages and components, that are running in the client, you should use for Logging `this.$logger` + +this.$logger.trace("Trace or Trance") +this.$logger.error("This is an error") +this.$logger.debug("This is a debugging log.") +this.$logger.info("This is a info log.") +this.$logger.warn("This is a warning log.") +this.$logger.fatal({...data, level: 'fatal'}) + +Please use this especially in catch blocks. It used pino as framework and can also provide logging. + +## Setup + +If you don't use Node 19 or lower than you need to work around with the node version manager. + +install node version mananger, register it with that code in your terminal. + +```sh +export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +``` + +Make sure you install node 18/19 and then run nvm use 18/19 before you continue. + +```bash +nvm install 19 +```` +```bash +nvm use 19 +```` + +Make sure to install the dependencies: + +```bash +# yarn +yarn install + +# npm +npm install + +# pnpm +pnpm install --shamefully-hoist +``` + +## Development Server + +Start the development server: + +```bash +npm run dev +``` +## Linting +Start the linting + +```bash +npm run lint +``` + +```bash +npm run lint:fix +``` + +## Production + +Build the application for production: + +```bash +npm run build +``` + +Locally preview production build: + +```bash +npm run preview +``` + +Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. + +## Container + +You can build the app as an Docker Container with the existing Dockerfile. The image can be deployed via an docker compose file that is not part of the current frontend project but an composition of the docker frontend and backend container. It can be found at our current strato development server and on gitea. + +## Mobile + +You can build the app for android and iOS !but this project still uses the browser API for accessing media of the user. By this reason the app actually not running on android nor iOs. + +Build the application for production: + +```bash +npm run generate +``` + +Create with capacitor the android build: +Capacitor should be installed already as an npm package, but check this first if you run into issues. + +```bash +npx cap add android +``` +```bash +npx cap add ios +``` + +Update with capacitor the android/ios build (after you changed something) + +```bash +npx cap sync android +``` +```bash +npx cap sync android +``` + +Open the app in Android Studio or Apple'S XCode + +```bash +npx cap open android +``` +```bash +npx cap open ios +``` + +Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. +You can also checkout capacitor, vue 3. \ No newline at end of file diff --git a/archive/AudioStateHandler.vue b/archive/AudioStateHandler.vue new file mode 100644 index 0000000..0cf506b --- /dev/null +++ b/archive/AudioStateHandler.vue @@ -0,0 +1,66 @@ + + diff --git a/archive/RNBOPlayer/index.vue b/archive/RNBOPlayer/index.vue new file mode 100644 index 0000000..711e489 --- /dev/null +++ b/archive/RNBOPlayer/index.vue @@ -0,0 +1,10 @@ + + + + diff --git a/archive/components/KeyboardPlayHandler.vue b/archive/components/KeyboardPlayHandler.vue new file mode 100644 index 0000000..6a0ff86 --- /dev/null +++ b/archive/components/KeyboardPlayHandler.vue @@ -0,0 +1,24 @@ + + + diff --git a/archive/components/old_AdaptiveNoiseGain.vue b/archive/components/old_AdaptiveNoiseGain.vue new file mode 100644 index 0000000..b272d8b --- /dev/null +++ b/archive/components/old_AdaptiveNoiseGain.vue @@ -0,0 +1,158 @@ + + diff --git a/archive/components/old_NoiseMusicGainLagoon.vue b/archive/components/old_NoiseMusicGainLagoon.vue new file mode 100644 index 0000000..493516d --- /dev/null +++ b/archive/components/old_NoiseMusicGainLagoon.vue @@ -0,0 +1,128 @@ + + diff --git a/archive/components/old_NoiseMusicGainMeadow.vue b/archive/components/old_NoiseMusicGainMeadow.vue new file mode 100644 index 0000000..0ba2646 --- /dev/null +++ b/archive/components/old_NoiseMusicGainMeadow.vue @@ -0,0 +1,123 @@ + + diff --git a/archive/components/old_NoiseMusicGainMeadowAudioElement2.vue b/archive/components/old_NoiseMusicGainMeadowAudioElement2.vue new file mode 100644 index 0000000..af25a09 --- /dev/null +++ b/archive/components/old_NoiseMusicGainMeadowAudioElement2.vue @@ -0,0 +1,117 @@ + + diff --git a/archive/components/old_NoiseMusicGainTropics.vue b/archive/components/old_NoiseMusicGainTropics.vue new file mode 100644 index 0000000..b4d85b0 --- /dev/null +++ b/archive/components/old_NoiseMusicGainTropics.vue @@ -0,0 +1,122 @@ + + diff --git a/archive/components/tests/AudioElementManager.vue b/archive/components/tests/AudioElementManager.vue new file mode 100644 index 0000000..b3a0fb7 --- /dev/null +++ b/archive/components/tests/AudioElementManager.vue @@ -0,0 +1,375 @@ + + + + diff --git a/archive/components/tests/AudioNoiseTest.vue b/archive/components/tests/AudioNoiseTest.vue new file mode 100644 index 0000000..6b5dd22 --- /dev/null +++ b/archive/components/tests/AudioNoiseTest.vue @@ -0,0 +1,498 @@ + + + + diff --git a/archive/components/tests/AudioNoiseTest2.vue b/archive/components/tests/AudioNoiseTest2.vue new file mode 100644 index 0000000..e826a7a --- /dev/null +++ b/archive/components/tests/AudioNoiseTest2.vue @@ -0,0 +1,606 @@ + + + + diff --git a/archive/components/tests/MicNoisePatchMusic2.vue b/archive/components/tests/MicNoisePatchMusic2.vue new file mode 100644 index 0000000..380a511 --- /dev/null +++ b/archive/components/tests/MicNoisePatchMusic2.vue @@ -0,0 +1,110 @@ + + diff --git a/archive/components/tests/NoiseMusicGainPlayPauseDevice.vue b/archive/components/tests/NoiseMusicGainPlayPauseDevice.vue new file mode 100644 index 0000000..85677d5 --- /dev/null +++ b/archive/components/tests/NoiseMusicGainPlayPauseDevice.vue @@ -0,0 +1,192 @@ + + diff --git a/archive/components/tests/NoisePatchMusic_glitchOnLoad.vue b/archive/components/tests/NoisePatchMusic_glitchOnLoad.vue new file mode 100644 index 0000000..f35c535 --- /dev/null +++ b/archive/components/tests/NoisePatchMusic_glitchOnLoad.vue @@ -0,0 +1,97 @@ + + diff --git a/archive/components/tests/RNBOPlayer.vue b/archive/components/tests/RNBOPlayer.vue new file mode 100644 index 0000000..2703e76 --- /dev/null +++ b/archive/components/tests/RNBOPlayer.vue @@ -0,0 +1,676 @@ + + + + + diff --git a/archive/demo/index.vue b/archive/demo/index.vue new file mode 100644 index 0000000..9eb5f6b --- /dev/null +++ b/archive/demo/index.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/archive/pages/experiments/AllGainPlayPauseSkip.vue b/archive/pages/experiments/AllGainPlayPauseSkip.vue new file mode 100644 index 0000000..122523f --- /dev/null +++ b/archive/pages/experiments/AllGainPlayPauseSkip.vue @@ -0,0 +1,376 @@ + + + + diff --git a/archive/pages/experiments/AudioElementManager2.vue b/archive/pages/experiments/AudioElementManager2.vue new file mode 100644 index 0000000..0345e7e --- /dev/null +++ b/archive/pages/experiments/AudioElementManager2.vue @@ -0,0 +1,7 @@ + + + diff --git a/archive/pages/experiments/audioElementManager.vue b/archive/pages/experiments/audioElementManager.vue new file mode 100644 index 0000000..d014ac6 --- /dev/null +++ b/archive/pages/experiments/audioElementManager.vue @@ -0,0 +1,365 @@ +