Skip to content

Product Biografie First

First Wongsrila edited this page Jul 7, 2023 · 3 revisions

Week 1

In de eerste week zijn we dinsdag officieel begonnen. Op dinsdag hadden we onze eerste ontmoeting met onze opdrachtgever. Het team bestaat uit Giovanni en ik. Een klein team. Wij hebben het project Hitloop gekregen en de opdracht luidt als volgt: “Hoe kan Responsible IT innovatieve, gebruiksvriendelijke grafische en auditieve interfaces ontwikkelen voor een touch interface op een tablet, zoals een iPad, die gebruikers in staat stellen om snel en gemakkelijk deuntjes te maken, terwijl we tegelijkertijd experimenteren met unieke interfaces en interacties die niet gebaseerd zijn op bestaande concepten?”

Voordat wij de briefing hadden met Yuri, onze opdrachtgever, hebben wij wat vragen voorbereid die handig waren op te stellen om de opdracht beter te begrijpen.

Contactgegevens

Info over Yuri?

  • Zijn er andere stakeholders waar we eventueel mee moeten samenwerken?
  • Hoe kunnen we het beste met elkaar communiceren?
  • Wie kan ons toegang verlenen tot relevante documentatie, data of bronnen?
  • Achtergrondinformatie:
  • Kan je ons wat meer vertellen over hoe de samenwerking met Thunder Boom Records is ontstaan?
  • Hoe is het idee van de Hitloop ontstaan?
  • Wat voor reacties hebben vorige prototypes van Hitloop gekregen?
  • Zijn er specifieke huisstijl richtlijnen waar we ons aan moeten houden?
  • Zijn er bepaalde eisen waar we rekening mee moeten houden?

Opdrachtomschrijving

Kun je specifieke functies of kenmerken noemen die je graag zou willen zien in de interface van Hitloop? (user-stories) Moet het ontwerp zich richten op een specifiek besturingssysteem voor tablets (iOS, Android, etc.) of moet het platform onafhankelijk zijn? Zijn er specifieke stijlen of ontwerp elementen die u wilt vermijden? Heeft u voorbeelden van bestaande interfaces die u aantrekkelijk of effectief vindt? Zijn er specifieke technologieën die we moeten gebruiken of juist vermijden bij het ontwikkelen van de interface?

Aanleiding:

Wat heeft tot dit project geleid? Zijn er specifieke problemen of kansen die je wilt aanpakken? Wat is de belangrijkste uitdaging die dit project zal oplossen?

Doelstelling:

Wat zijn de belangrijkste doelen die je wilt bereiken met dit project? Hoe zal je het succes van dit project meten? Wat zijn de verwachte voordelen voor de eindgebruikers? Zijn er meetbare KPI's geassocieerd met dit project? Wat zijn de korte termijn doelen van dit project?

Randvoorwaarden:

Zijn er juridische regelgevingen waarmee we rekening mee moeten houden bij het ontwerp en de ontwikkeling van dit project? Zijn er technische beperkingen waar we rekening mee moeten houden? Heeft u specifieke vereisten met betrekking tot data beveiliging en privacy? Zijn er geografische of culturele overwegingen die van invloed kunnen zijn op het project?

Gebruikers van het eindresultaat

Hoe verwacht je dat de gebruikers Hitloop zullen gebruiken? Zijn er specifieke toegankelijkheidseisen voor de gebruikersinterface? Wat zijn de gebruikers verwachtingen voor het gebruik van dit instrument? Heeft u al feedback van de gebruikers gekregen die we kunnen gebruiken?

Relatie met andere projecten

Zijn er specifieke gebruikers/persona's waar we rekening mee moeten houden? Naast de User Stories die in de Readme staan. Zijn er gedragskenmerken van de gebruikers die we moeten begrijpen? Zijn er in het verleden soortgelijke projecten uitgevoerd en zo ja, wat kunnen we daarvan leren? Hoe zal dit project integreren met andere lopende initiatieven? Zijn die er? Zijn er andere projecten of systemen die mogelijk kunnen worden beïnvloed door dit project? Nadat wij de briefing hadden, gingen we gelijk aan de slag. Giovanni had het project opgezet in Vue.js omdat ik hier nog niet zoveel ervaring mee heb. Daarom ben ik de eerste week ook gelijk begonnen met het leren van Vue.js en Tone.js. Vue.js is nog best lastig voor mij dus probeer ook zoveel mogelijk vanilla javascript te schrijven, wat gelukkig redelijk goed werkt met Vue.js. Ook heb ik lopen worstelen met tone.js omdat dit een zeer complexe en ingewikkelde library is waarmee je muziekinstrumenten kan maken. Hiervoor heb ik vooral veel documentatie gelezen en op google naar voorbeelden gezocht.

Wij hebben uiteindelijk een eerste prototype opgeleverd met de basisfunctionaliteiten van de Hitloop sequencer. Het doel was om de huidige Hitloop over te zetten naar het Vu.js project van ons.

Week 2

Na ons eerste feedbackgesprek moesten we van Yuri nu echt gaan experimenteren met verschillende soorten vormgevingen. De eerste paar dagen zat ik best vast met hoe de app eruit moest zien. Ik was namelijk nog best in de war met de eisen die verwacht werden. Volgens Yuri moesten we iets heel anders maken dan een ordinaire muzieksequencer, dus echt experimenteren met unieke vormgevingen zoals golven etc. Maar in de debrief stond ook dat het gebruiksvriendelijk en duidelijk moet zijn voor een muzikant/producer. En om dit te kunnen doen lijkt het logischer om juist iets te maken waar de producers al mee bekend zijn.

Uiteindelijk ben ik toch op wat ideeën gekomen wat potentie heeft voor Hitloop. Het concept is dat je een circulaire sequencer hebt die verschillende kleuren en ringen heeft.

Dit concept leek ons ook super vet. Echter bleek dit toch best ingewikkeld te zijn om de circle “dashes” te implementeren in de huidige code. Elke dash van een cirkel moet namelijk klikbaar zijn en de dashes moeten in een loop zitten. We dachten eerst om de cirkels figma te maken en dat individuele svgs te exporteren maar dit werkte dus niet omdat het geloopt moet worden. Uiteindelijk hebben wij het opgelost met svg lines en de styling daarvan met een formule dat in een cirkel loopt. Ook hebben wij de stappen in een rij verkleind van 16 stappen naar 8 omdat het anders te krap wordt.

<svg viewBox="0 0 200 200">
<circle cx="100" cy="100" r="80" fill="none" stroke="none" />
<g transform="translate(100,100)">
<path
v-for="(step, stepIndex) in columns"
class="arc-item"
:key="stepIndex"
:d="describeArc(0, 0, 80, getStartAngle(stepIndex), getEndAngle(stepIndex))"
:class="{ active: row.steps[stepIndex], highlighted: stepIndex === highlighted }"
@click="$emit('toggleStep', row, stepIndex)"
stroke-width="15"
stroke="blue"
fill="none"
stroke-linecap="round"
:name="stepIndex"
/>
</g>
</svg>

Week 3

Dit waren de doelen van voor week 3:

  • experimenteren met de circles
  • in elkaar, dunne lijn met rondje etc
  • maak meerdere versies en kies de leukste uit voor volgende week.
  • zelf midi maken laten genereren eventueel ook bewerken.
  • data opslaan met structuur die ook geladen kan worden.
  • geluid visualisatie experimenteren.

Dit was een lastige week voor ons. We wilde namelijk geluiden kunnen visualiseren en meer geanimeerde interactie toevoegen aan de Hitloop. Dit was echter super moeilijk om te doen. Ik ben gaan kijken naar d3 data visualization. Dit is was te complex om in een korte tijd helemaal te verwerken in de applicatie.

Wat we ook als concept hadden is om een cirkel in cirkel sequencer te maken. circle sequencer

<script setup>
import { useSequenceStore } from '@/stores/sequence'
import { storeToRefs } from 'pinia'
import { ref } from 'vue'

const props = defineProps({
  id: Number,
  sampleTypeList: Array,
  sampleData: Array,
  item: Object,
  url: String,
  columns: Number,
  row: Object,
  highlighted: Number,
  col: Number
})

const store = useSequenceStore()
// store values to vuejs ref
const { currentStepIndex } = storeToRefs(store)

const { toggleStep } = store

const gapSize = Math.PI / 10

function describeArcOld(x, y, radius, startAngle, endAngle) {
  const start = polarToCartesian(x, y, radius, endAngle)
  const end = polarToCartesian(x, y, radius, startAngle)
  const largeArcFlag = endAngle - startAngle <= Math.PI ? '0' : '1'
  const d = ['M', start.x, start.y, 'A', radius, radius, 0, largeArcFlag, 0, end.x, end.y].join(' ')
  return d
}

function describeArc(x, y, radius, startAngle, endAngle) {
  const start = polarToCartesian(x, y, radius, endAngle)
  const end = polarToCartesian(x, y, radius, startAngle)
  const largeArcFlag = endAngle - startAngle <= Math.PI ? '0' : '1'
  const d = ['M', start.x, start.y, 'A', radius, radius, 0, largeArcFlag, 0, end.x, end.y].join(' ')
  return d
}

function polarToCartesian(centerX, centerY, radius, angleInRadians) {
  const x = centerX + radius * Math.cos(angleInRadians)
  const y = centerY + radius * Math.sin(angleInRadians)
  return { x, y }
}

function getStartAngle(index) {
  return (2 * Math.PI * index) / props.columns + gapSize / 2
}

function getEndAngle(index) {
  return (2 * Math.PI * (index + 1)) / props.columns - gapSize / 2
}
</script>

<template>
  <svg viewBox="0 0 200 200">
    <circle cx="100" cy="100" r="80" fill="none" stroke="none" />
    <g transform="translate(100,100)">
      <path
        v-for="(step, stepIndex) in props.columns"
        class="arc-item"
        :key="stepIndex"
        :d="describeArc(0, 0, 80, getStartAngle(stepIndex), getEndAngle(stepIndex))"
        :class="{ active: row.steps[stepIndex], highlighted: stepIndex === highlighted }"
        @click="toggleStep(row, stepIndex)"
        stroke-width="15"
        stroke="blue"
        fill="none"
        stroke-linecap="round"
        :name="stepIndex"
      />
    </g>
  </svg>
</template>

<style lang="scss" scoped>
.arc-item {
  stroke: #fff ;
  transition: all 0.2s;
}
.active {
  stroke-opacity: 50%;
  stroke: var(--color-green);


}

.highlighted {
  stroke-opacity: 10%;
  stroke: var(--color-text)

  // stroke: green;
}

.highlighted.active {
  stroke-opacity: 100%;
  stroke-width: 22;
  transform: scale(1.75);
  stroke: var(--color-text)
}

Dit was dus niet gelukt omdat we zaten te stoeien met het optimaliseren en überhaupt verschillende ringen te krijgen. Dit heeft ons ook veel tijd gekost.

Week 4

In deze week zijn we wat stappen terug gegaan omdat we vorige week helemaal vast zaten met wat we moesten en konden doen. Giovanni en ik hadden besloten om het concept van een step sequencer aan te houden maar dit uit te gaan breiden met het verbeteren/bewerken van de audio. Hiervoor hebben wij geluidseffecten toegevoegd zoals de reverb en volume.

watch(
  () => props.volume,
  (nVol) => {
    console.log(`vol is: ${nVol}`)
    if (vol) {
      vol.set({ volume: nVol })
    }
  }
)

watch(
  () => props.reverb,
  (newRev) => {
    console.log(newRev)

    if (newRev > 0.001 && newRev !== 0 && newRev !== null) {
      rev.set({ decay: newRev })
      sampler.connect(rev)
    } else {
      sampler.disconnect(rev)
    }
  }
)
<div class="input-group">
  <label for="reverb">Reverb:</label>
  <input
    id="reverb"
    type="range"
    min="0"
    max="10"
    @change="$emit('update:reverb', $event.target.value)"
    :value="reverb"
    step="0.5"
  />
</div>
<div class="input-group">
  <label for="volume">Volume:</label>
  <input
    id="volume"
    type="range"
    min="-70"
    max="0"
    @input="$emit('update:volume', $event.target.value)"
    :value="volume"
    step="1"
  />
</div>

Ik heb ook een redesign gemaakt voor de Hitloop. hitloop

We hebben met het design, de geluidseffecten per rij in modal gestopt zodat dit mooi overzichtelijk blijft. Tijdens ons feedback gesprek met de opdrachtgever, hebben wij hem verteld over de onze stappen en dat we een stapje terug hebben gedaan van de fancy animaties. Hij begreep gelukkig wel onze keuze en als vervanging vertelde hij dat hij dus blij was dat we gingen focussen op de geluidseffecten.

Week 5

In deze week was het echt vooral het afronden van het project en alle laatste functionaliteiten die we nog willen verwerken, ook uitvoeren. Een belangrijke functie die we nog hebben toegevoegd is het random genereren van een sequence. Dit haalt de code uit een object met true's en falses. Met deze functie hoeft een gebruiker niet altijd zelf een sequence te maken maar kan hij zich geïnspireerd laten raken door een gegenereerde sequence.

const randomArrays = [
    [
      true,
      false,
      false,
      false,
      true,
      false,
      false,
      false,
      true,
      false,
      false,
      false,
      true,
      false,
      false,
      false
    ],
    [
      true,
      false,
      true,
      true,
      true,
      false,
      true,
      true,
      true,
      false,
      true,
      true,
      true,
      false,
      true,
      true
    ],
    [
      false,
      true,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      true,
      false,
      false,
      false,
      false,
      false
    ],
    [
      false,
      false,
      true,
      false,
      false,
      false,
      true,
      false,
      false,
      false,
      true,
      false,
      false,
      false,
      true,
      false
    ]
  ]

  const randomSequenceSteps = (id) => {
    let randomIndex = Math.floor(Math.random() * randomArrays.length)

    // Retrieve the random item from the array
    let randomItem = randomArrays[randomIndex]
    console.log('clicked')
    return (sequenceData.value[id].steps = randomArrays[randomIndex])
  }

Ook heb ik de UI wat verbeterd met duidelijkere titels en de iconen verbeterd.