11<template >
2- <div class =" flex flex-col items-center gap-4 pt-8 text-center" >
3- <label :for =" note_frequency_text" >
4- {{ note_frequency_text }}
5- <br />
6- <input
7- :id =" note_frequency_text"
8- v-model =" note_frequency"
9- type =" number"
10- :placeholder =" note_frequency_text"
11- />
12- <br />
13- <input type =" range" v-model =" note_frequency" :id =" note_frequency_text" min =" 20" max =" 2000" />
14- </label >
15- <span class =" relative inline-flex" >
16- <button @click =" playNote()" >
17- <span > {{ play_button_text }}</span >
18- <span v-if =" is_playing" class =" absolute top-0 right-0 -mt-1 -mr-1 flex size-3" >
19- <span
20- class =" absolute h-full w-full animate-ping rounded-full bg-[var(--caret-color)] opacity-75"
21- ></span >
22- <span class =" relative size-3 rounded-full bg-[var(--main-color)]" ></span >
23- </span >
24- </button >
25- </span >
26-
27- <label :for =" volume_text" >
28- {{ volume_text }}
29- <input :id =" volume_text" type =" range" v-model =" volume" min =" 0" max =" 100" />
30- {{ volume }}%
31- </label >
32- <label :for =" oscillator_type_text" class =" align-middle" >
33- {{ oscillator_type_text }}
34- <span class =" align-middle mr-1" :class =" oscillator_icon" ></span >
35- <select v-model =" oscillator_type" :id =" oscillator_type_text" >
36- <option :key =" index" v-for =" (type, index) in oscillator_types" :value =" type" >
37- {{ type }}
38- </option >
39- </select >
40- </label >
2+ <div class =" flex flex-col gap-4 w-[40vw]" >
3+ <div class =" flex flex-col bordered" >
4+ <label :for =" toggle_temperament_text" >
5+ {{ toggle_temperament_text }}
6+ <div >
7+ <button
8+ @click =" toggle_temperament = true"
9+ :class =" { 'text-[var(--bg-color)] !bg-[var(--text-color)]': toggle_temperament }"
10+ >
11+ ON
12+ </button >
13+ <button
14+ @click =" toggle_temperament = false"
15+ :class =" { 'text-[var(--bg-color)] !bg-[var(--text-color)]': !toggle_temperament }"
16+ >
17+ OFF
18+ </button >
19+ </div >
20+ </label >
21+
22+ <hr />
23+ <div class =" flex flex-col gap-4" :disabled =" !toggle_temperament || null" >
24+ <label :for =" concert_pitch_text" >
25+ {{ concert_pitch_text }}
26+ <i class =" icon-[ph--bell-simple]" ></i >
27+ <br />
28+ <input
29+ :id =" concert_pitch_text"
30+ v-model =" concert_pitch"
31+ type =" number"
32+ :placeholder =" concert_pitch_text"
33+ :disabled =" !toggle_temperament"
34+ />
35+ </label >
36+
37+ <label :for =" temperament_text" class =" align-middle" >
38+ {{ temperament_text }}
39+ <i class =" icon-[ph--divide] mr-2" ></i >
40+ <select v-model =" temperament" :id =" temperament_text" :disabled =" !toggle_temperament" >
41+ <option :key =" index" v-for =" (type, index) in temperaments" :value =" type" >
42+ {{ type }}
43+ </option >
44+ </select >
45+ </label >
46+
47+ <label :for =" note_name_text" >
48+ {{ note_name_text }}
49+ <i class =" icon-[ph--music-note-simple]" ></i >
50+ <br />
51+ <input
52+ :id =" note_name_text"
53+ v-model =" note_name"
54+ type =" text"
55+ :placeholder =" note_name_text"
56+ :disabled =" !toggle_temperament"
57+ />
58+ </label >
59+
60+ <label :for =" steps_text" >
61+ {{ steps_text }}
62+ <i class =" icon-[ph--ladder-simple]" ></i >
63+ <br />
64+ <input
65+ :id =" steps_text"
66+ v-model =" steps"
67+ type =" number"
68+ :placeholder =" steps_text"
69+ :disabled =" !toggle_temperament"
70+ :min =" MIN_STEPS"
71+ :max =" MAX_STEPS"
72+ />
73+ <br />
74+ <input
75+ type =" range"
76+ v-model.number =" steps"
77+ :id =" steps_text"
78+ :min =" MIN_STEPS"
79+ :max =" MAX_STEPS"
80+ :disabled =" !toggle_temperament"
81+ />
82+ </label >
83+ </div >
84+ </div >
85+
86+ <div class =" flex flex-col bordered" >
87+ <label :for =" note_frequency_text" >
88+ {{ note_frequency_text }}
89+ <i class =" icon-[ph--bell-simple-ringing]" ></i >
90+ <br />
91+ <input
92+ :id =" note_frequency_text"
93+ v-model =" note_frequency"
94+ type =" number"
95+ :placeholder =" note_frequency_text"
96+ :min =" MIN_FREQEUNCY"
97+ :max =" MAX_FREQEUNCY"
98+ />
99+ <br />
100+ <input
101+ type =" range"
102+ v-model =" note_frequency"
103+ :id =" note_frequency_text"
104+ :min =" MIN_FREQEUNCY"
105+ :max =" MAX_FREQEUNCY"
106+ />
107+ </label >
108+ <span class =" relative inline-flex mx-auto" >
109+ <button @click =" playNote()" >
110+ <i v-if =" is_playing" class =" icon-[ph--megaphone] mr-2" ></i >
111+ <span >{{ play_button_text }}</span >
112+
113+ <span v-if =" is_playing" class =" absolute top-0 right-0 -mt-1 -mr-1 flex size-3" >
114+ <span
115+ class =" absolute h-full w-full animate-ping rounded-full bg-[var(--caret-color)] opacity-75"
116+ ></span >
117+ <span class =" relative size-3 rounded-full bg-[var(--main-color)]" ></span >
118+ </span >
119+ </button >
120+ </span >
121+
122+ <label :for =" volume_text" >
123+ {{ volume_text }}
124+ <i class =" icon-[ph--speaker-high]" ></i >
125+ <input :id =" volume_text" type =" range" v-model =" volume" min =" 0" max =" 100" />
126+ {{ volume }}%
127+ </label >
128+ <label :for =" oscillator_type_text" class =" align-middle" >
129+ {{ oscillator_type_text }}
130+ <span class =" align-middle mr-2" :class =" oscillator_icon" ></span >
131+ <select v-model =" oscillator_type" :id =" oscillator_type_text" >
132+ <option :key =" index" v-for =" (type, index) in oscillator_types" :value =" type" >
133+ {{ type }}
134+ </option >
135+ </select >
136+ </label >
137+ </div >
41138 </div >
42139</template >
43140
@@ -51,7 +148,7 @@ const note_frequency_text = 'Frequency'
51148const np = new notePlayer ()
52149
53150const is_playing = ref (false )
54- const play_button_text = computed (() => (! is_playing .value ? ' Play note' : ' 🔊 Playing note...' ))
151+ const play_button_text = computed (() => (! is_playing .value ? ' Play note' : ' Playing note...' ))
55152
56153function playNote() {
57154 if (! is_playing .value ) {
@@ -65,6 +162,7 @@ function playNote() {
65162
66163watch (note_frequency , () => {
67164 np .setFrequency (note_frequency .value )
165+ if (toggle_temperament .value ) steps .value = np .getStepsFromFrequency (note_frequency .value )
68166})
69167
70168const volume = ref (50 )
@@ -73,13 +171,54 @@ watch(volume, () => {
73171 np .setGain (volume .value / 100 )
74172})
75173
76- const oscillator_types = ref <OscillatorType []>([' sawtooth' , ' sine' , ' square' , ' triangle' ])
77- const oscillator_type = ref <OscillatorType >(' sine' )
78174const oscillator_type_text = ' Oscillator type'
175+ const oscillator_types = ref <OscillatorType []>([' sine' , ' square' , ' triangle' , ' sawtooth' ])
176+ const oscillator_type = ref <OscillatorType >(oscillator_types .value [0 ])
79177const oscillator_icon = computed (
80178 () => ` icon-[ph--wave-${oscillator_type .value }${is_playing .value ? ' -duotone' : ' ' }] ` ,
81179)
82180watch (oscillator_type , () => {
83181 np .setOscillatorType (oscillator_type .value )
84182})
183+
184+ const toggle_temperament = ref (true )
185+ const toggle_temperament_text = ' Toggle Tone Equal Temperament'
186+
187+ const concert_pitch_text = ' A4 Frequency (Concert pitch)'
188+ const concert_pitch = ref (440 )
189+ watch (concert_pitch , () => {
190+ np .setConcertPitch (concert_pitch .value )
191+ updateLowestMetrics ()
192+ })
193+
194+ const lowest_metrics = ref (np .getLowestMetrics ())
195+ function updateLowestMetrics() {
196+ lowest_metrics .value = np .getLowestMetrics ()
197+ }
198+ const MIN_FREQEUNCY = computed (() => lowest_metrics .value .frequency )
199+ const MIN_STEPS = computed (() => lowest_metrics .value .step )
200+ const MAX_FREQEUNCY = 20000
201+ const MAX_STEPS = np .getStepsFromFrequency (MAX_FREQEUNCY )
202+
203+ type Temperament = 12
204+ const temperament_text = ref (' Temperament' )
205+ const temperaments = ref <Temperament []>([12 ])
206+ const temperament = ref <Temperament >(temperaments .value [0 ])
207+ watch (temperament , () => {
208+ np .setTemperament (temperament .value )
209+ updateLowestMetrics ()
210+ })
211+
212+ const note_name_text = ' Note name'
213+ const note_name = ref (' A4' )
214+ watch (note_name , () => {
215+ note_frequency .value = np .getFrequencyFromNoteName (note_name .value )
216+ })
217+
218+ const steps_text = ' Steps'
219+ const steps = ref <number >(0 )
220+ watch (steps , () => {
221+ note_frequency .value = np .getFrenquencyFromSteps (steps .value )
222+ note_name .value = np .getNoteNameFromSteps (steps .value )
223+ })
85224 </script >
0 commit comments