電子書籍の厳選無料作品が豊富!

いつもお世話になっています。
原因を探しやすくするために、必要最小限のコードを書きおろしました。
次のコードは、ソとラとシの音を出す鍵盤アプリです。
指が鍵盤に触れている間は音が鳴り、指を離すとその音が止まります。
しかし、このアプリで演奏していると、たまに指を離しても音が止まらなくなってしまいます。
その原因を教えてください。
コードが読みにくくてスミマセン
(>_<)
<body style="margin: 0">
<canvas></canvas>
<script src="jquery.min.js"></script>
<script>
const 鍵盤 = $('canvas'), 鍵 = [{音階: -200}, {音階: 0}, {音階: 200}], 幅 = innerWidth / 3
let 音声
鍵盤[0].width = innerWidth
鍵盤.one('touchstart', () => 音声 = new AudioContext)
鍵盤.on('touchstart', e => {for(const 点 of e.originalEvent.touches) 発音(点)})
鍵盤.on('touchend', e => {for(const 点 of e.originalEvent.changedTouches) 発音(点, 1)})

function 発音(e, 停止) {
現鍵 = 鍵[e.clientX < 幅 ? 0 : e.clientX < 幅 * 2 ? 1 : 2]
if(停止) {
現鍵.発振器.stop()
現鍵.発音 = 0
} else if(!現鍵.発音) {
(現鍵.発振器 = new OscillatorNode(音声, {detune: 現鍵.音階})).connect(音声.destination)
現鍵.発振器.start()
現鍵.発音 = 1
}
}
</script>
</body>

  • 画像を添付する (ファイルサイズ:10MB以内、ファイル形式:JPG/GIF/PNG)
  • 今の自分の気分スタンプを選ぼう!
あと4000文字

A 回答 (5件)

No4です。



スマホも詳しくはありませんけれど・・
touchイベントはmouseイベントとは異なり、複数のイベント発生に対応しているので、No1にも書きましたが扱いが変わるはずです。
(mouseによるイベントは1ヶ所に限定されています)

そのあたりを考慮した処理にしておけば良いのではないでしょうか?
https://developer.mozilla.org/ja/docs/Web/API/To …
https://qiita.com/yamazaki3104/items/1f550c589b1 …


※ ご質問の内容が当初のものとは違うものになってきてしまったので、別のスレッドにした方が良いかも知れませんね。
    • good
    • 0
この回答へのお礼

お返事ありがとうございます。
スマホは、画面は小さいですが、マウスではできない操作ができるので、そこはすごいですね。
しかしPCとスマホの両方に対応させようとすると、コードが複雑になるのでキツイです。

キャンバスでのタッチのように、同じ要素内での複数箇所タッチなら簡単に拾えるのですが、
キャンバスとラジオボタンなど、異なる要素を同時にタッチした場合に、その両方のイベントハンドラーを動かすのが、うまくいかずに、てこずっています。

仰せのとおり、新たなスレッドを作らせていただきます。

お礼日時:2024/07/21 08:08

No3です。



>鍵盤以外のスイッチやスライダー類もすべてキャンバスに
>描画する必要があるのではと考えています。
シンセサイザーの仕組み自体を知りませんので、API等の制限などに関してはまったくわかりませんけれど・・
HTML要素のイベントを拾うことに関しては同じはずなので、canvasであれ他の要素であれ同じことではないかと想像しますが・・
(HTMLでできないことが、canvasならできるという事は無いと思います)

先人たちの作成したものを見てみると、音を出しながらの操作を受け付けているようですので、可能なのではないでしょうか?
http://aikelab.net/websynth/
https://koodori.netlify.app/
    • good
    • 0
この回答へのお礼

先生はjavascriptの達人であり、シンセサイザーの達人でない旨承知しました。
スミマセン、うまく説明できていませんでした。
改めて質問させてください。
問題を再現するための必要最小限のコードを書きました。
このアプリは、ラジオボタン2個と、鍵に見立てたdiv要素1個からなります。
鍵を押すと黒くなり、離すと白に戻ります。
このアプリでは、ラジオボタンを単独で操作する事は可能ですが、
鍵を押したまま、その時空いている指でラジオボタンを押そうとしても、ラジオボタンは反応しません。

鍵から指を離さずに、ラジオボタンを操作するにはどうすれば良いかご教示ください
m(__)m

<input type="radio" name="t">
<input type="radio" name="t">
<div style="padding: 1em; border: 1px solid"></div>
<script src="jquery.min.js"></script>
<script>
const 鍵 = $('div')
鍵.on('touchstart', () => 鍵.css('background', '#000'))
鍵.on('touchend', () => 鍵.css('background', '#fff'))
</script>

お礼日時:2024/07/18 01:56

No2です。



>私は最初div要素を並べたのですが、先生なら何の要素を
>並べて鍵盤を作りますか。
先生ではありません。ただの、遊びで独学しただけの者です。

HTMLで行うのなら、別に要素の種類に拘る必要もないと思います。
ごく一般的なら、divとかspanでしょうか。(ul-liもあるのかも)
単に矩形を並べるだけなら簡単ですし、白鍵だけ並べてから黒鍵を並べる方法や、鍵盤の順に並べる方法など、記述順もいろいろ考えられそうです。
また、少し凝って斜めの影(=押された際の影など)を付けるなども考えるのなら、SVGの方がやり易そうにも思います。

以下は
 ・単に矩形を並べるだけで表示
 ・鍵盤の順に記述する
という前提での一例です。(あくまでも一例です)

<!DOCTYPE HTML>
<html lang="ja">
<head><title>Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#keybord {
display: flex;
width: max-content;
margin: 0 auto;
}
#keybord div {
position: relative;
}
#keybord div::after {
content: "";
display: block;
width: 50px; height: 200px;
margin-right: 1px;
background-color: white;
border: 1px solid gray;
border-radius:0 0 4px 4px;
}
#keybord div[class$="#"]::after {
content: "";
position: absolute;
width: 30px; height: 120px;
margin-right: 0;
background-color: black;
transform: translate(-50%, 0);
z-index: 1;
}
</style>
</head>
<body>
<div id="keybord">
<div class="C1"></div>
<div class="C1#"></div>
<div class="D1"></div>
<div class="D1#"></div>
<div class="E1"></div>
<div class="F1"></div>
<div class="F1#"></div>
<div class="G1"></div>
<div class="G1#"></div>
<div class="A2"></div>
<div class="A2#"></div>
<div class="B2"></div>
<div class="C2"></div>
</div>
</body>
</html>
    • good
    • 0
この回答へのお礼

遊びで独学されていたのですね。
しかし私が一晩中悩んでいた問題を一瞬で解決する腕をお持ちなので、やはり先生と呼ばせていただくしかありません。

鍵に使う要素は特に何でも構わないのですね。しかし、あえて選ぶなら鍵1個1個をブロック要素と見なし、divがまあ妥当かなと思いました。

SVGは、コードが長くなってしまうのと、うまく表示できない機種がけっこうあるのと、勉強する必要がある事から、辞退しました。

先生のコード中には、見た事ないセレクタや式が結構ありますが、これを読み込んだら美しい鍵盤が表示されました。

これにて意気揚々と作成を再開させました。

しかし、ここで新たな問題が発生しました。

シンセサイザーの一般的な機能でもある、音を変えるラジオボタンを鍵盤の上段に追加しようとしました。

しかしブラウザーの仕様なのか、鍵盤操作中はラジオボタンが操作できませんでした。

恐らく複数の要素に同時にフォーカスを与えるというのが難しいのではと考えています。

例えばドの音を出している最中に、ラジオボタンを操作して、波形を正弦波から矩形波に変更するような奏法も対応したいと考えています。

これを実現させるには、鍵盤以外のスイッチやスライダー類もすべてキャンバスに描画する必要があるのではと考えています。

この認識は正しいですか。

先生の見解を教えてください。
m(__)m

お礼日時:2024/07/17 22:15

No1です。



>指をスライドして離したら簡単に再現できました。
多分、原因はNo1に記したようなことではないかと推測します。

対応法としては、「単音演奏」が前提なら、endイベントで「発音している音を停止する」という処理にしておけば、意図したものになると思います。


一方で、タッチは複数の指を許可していたと思いますので、「和音演奏」も考慮するのであれば、処理方法全体を見直した方がよさそうに思われます。

また、画面表示が鍵盤を模している場合に、発音している鍵の図を「押し下げの図」に変えて、視覚的にも表現するなどを考慮しているのであれば、canvasでも可能ですが、各鍵が個別の要素になっている方が制御しやすいのではないかと思います。
各鍵をHTML要素やSVG要素にしておいた方が簡単かも知れませんね。
    • good
    • 0
この回答へのお礼

お返事ありがとうございます。
発音した音をイベントのidentifierと供に記憶して、指を離した時にその音を停止するようにしました。
またtouchmoveイベント用の動きも作り、かなり意図した通りに動くようになりました。
しかし、まだたまーに音が止まらなくなる事がありデバッグしていた所でした。
視覚的な表現は色を変えるぐらいしか考えていませんでしたので、他の要素に変えた方が簡単だと思いました。
最初はdiv要素をいっぱい並べて作ろうとしたのですが、うまく並べられずcanvasに妥協したという経緯があります。
しかし、未だデバッグに手間取っている事を考えると、やはり他の要素に変えた方が早いと思いました。
私は最初div要素を並べたのですが、先生なら何の要素を並べて鍵盤を作りますか。

お礼日時:2024/07/16 16:54

こんばんは



ざっと見ただけで、試してはいないので、違っているかもしれませんけれど・・

canvas全体の「touchstart」と「touchend」だけを拾っているようなので、
例えば、どこかにタッチして(=音が出始める)、別の領域にスライドしてから指を離した場合に、音を止める処理をするのは「別の領域」の音になっているのではないでしょうか?
もしそうなら、元の音は止まらないことになりませんか?
(領域境界に近い位置だと、スライドした意識はなくても上記が発生する可能性があると思われます。)
    • good
    • 0
この回答へのお礼

お返事ありがとうございます。
阿呆でした。
今まで再現する方法が分からなかったのですが、指をスライドして離したら簡単に再現できました。

お礼日時:2024/07/16 05:48

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A