我有RSI问题,尝试了30种不同的电脑键盘,都让我很痛苦。弹钢琴不会给我带来痛苦。我已经弹钢琴20年了,没有任何疼痛问题。我想知道是否有一种方法可以从MIDI键盘捕获MIDI并输出键盘敲击。我对MIDI一无所知,但我想要一些关于如何将这个信号转换成按键的指导。


当前回答

试试Bome的MIDI翻译器。

它可以跨平台工作,可以轻松地将任何MIDI输入转换为键盘,快速设置和配置,另外它是免费的个人使用。

有一个教程,快速提示:MIDI翻译- MIDI键击,如何轻松设置:

基本上,你可以做的事情有无限的可能性,包括和弦和修饰键。我用它作为我的现场音频设备来控制我的DAW使用我的钢琴,从来没有遇到过问题。

其他回答

在Java中,可以使用JMF (Java Media framework)来转换MIDI信号。 键盘设计的基本是易于使用,即用户界面;并把常用的字符/符号放在手边。

Java Sound Resources中的示例代码和API:示例:数字信号处理(DSP)有助于理解如何处理信号。

更多参考资料:

用控件处理音频 数字音频信号处理,第二版

实际上,我在这个工作了一段时间前,试图捕捉摇滚乐队鼓输入到我的计算机(做一个小Java自制鼓模拟器)无论如何,我问了一个问题在这里,时间延迟问题(有轮询代码在那里,以及我试图做的事情。)如果我能找到我的程序,我可以给你的代码,它使用第三方API (JInput)。

祝你好运。

试试Bome的MIDI翻译器。

它可以跨平台工作,可以轻松地将任何MIDI输入转换为键盘,快速设置和配置,另外它是免费的个人使用。

有一个教程,快速提示:MIDI翻译- MIDI键击,如何轻松设置:

基本上,你可以做的事情有无限的可能性,包括和弦和修饰键。我用它作为我的现场音频设备来控制我的DAW使用我的钢琴,从来没有遇到过问题。

使用. net DirectSound接口这样的东西来连接到MIDI设备应该是相当容易的。您需要识别目标MIDI设备,然后获取用于侦听传入消息的代码(有关于通过谷歌进行此操作的文章)。

由于您正在使用MIDI in作为键盘,因此基本上只需要检测两个MIDI消息,即打开和关闭。MIDI消息是三个数据字节,指定命令、音符和速度。note off只是音符号(有时“坏”MIDI堆栈以零速度发送音符,这也是你必须预料到的)。

一旦你有了转换它们的消息,从。net输出的键盘应该相当简单。

其他答案中有很多关于技术细节的建议;我只是想让你对实际的MIDI消息有一个概念。好运!

我已经很多年没有做过任何MIDI编程了,但是你的基本想法非常合理(没有双关语)。

MIDI是一连串的“事件”(或“信息”),其中最基本的两个是“开启”和“关闭”,它们都带有音符号(0 = C中C低5个八度,到127 = G中C以上G高5个八度,为半音)。这些事件在速度敏感(“触摸敏感”)的键盘上携带一个“速度”数字,其力度(你猜对了)在0到127之间。

Between velocity, chording, and the pedals, I'd think you could come up with quite a good "typing" interface for the piano keyboard. Chording in particular could be a very powerful technique — as I mentioned in the comments, it's why rank-and-file stenographers can use a stenotype machine to keep up with people talking for hours in a row, when even top-flight typists wouldn't be able to for any length of time via normal typewriter-style keyboards. As with machine stenography, you'd need a "dictionary" of the meanings of chords and sequences of chords. (Can you tell I used to work in the software side of machine stenography?)

要做到这一点,基本的部分是:

接收MIDI输入。不要尝试自己去做,使用一个库。编辑:显然,Java Sound API支持MIDI,包括从MIDI控制器接收事件。酷。本页也可能有用。 将数据转换为你想要发送的击键,例如通过我上面提到的字典。 输出击键到计算机。

为了最广泛地与软件兼容,您必须将其作为键盘设备驱动程序编写。这是操作系统的一个插件,用作键盘事件的源,与底层硬件(在您的例子中是钢琴键盘)通信。对于Windows和Linux,你可能会想要使用C语言。

However, since you're just generating keystrokes (not trying to intercept them, which I was trying to do years ago), you may be able to use whatever features the operating system has for sending artificial keystrokes. Windows has an interface for doing that (probably several, the one I'm thinking of is SendInput but I know there's some "journal" interface that does something similar), and I'm sure other operating systems do as well. That may well be sufficient for your purposes — it's where I'd start, because the device driver route is going to be awkward and you'd probably have to use a different language for it than Java. (I'm a big fan of Java, but the interfaces that operating systems use to talk to device drivers tend to be more easily consumed via C and similar.)


更新:更多关于和弦到按键的“字典”:

基本上,字典是一个trie(谢谢,@Adam),我们用最长前缀匹配进行搜索。细节:

In machine stenography, the stenographer writes by pressing multiple keys on the stenotype machine at the same time, then releasing them all. They call this a "stroke" of the keyboard; it's like playing a chord on the piano. Strokes frequently (but not always) correspond to a syllable of spoken language. Like syllables, sometimes one stroke (chord) has meaning all on its own, other times it only has meaning combined with following strokes. (Think "good" vs. "good" followed by "bye"). Although they'll be heavily influenced by the school at which they studied, each stenographer will have their own "dictionary" of what strokes they use to mean what, a dictionary they will continuously hone over the course of their working lives. The dictionary will have entries where the stenographic part ("steno", for short) is one stroke long, or multiple strokes long. Frequently, there will be several entries with the same starting stroke which are differentiated by their length and by the subsequent strokes. For instance (and I won't use real steno here, just placeholders), there may be these entries:

A     = alpha
A/B   = alphabet
A/B/C = alphabetic
A/C   = air conditioning
B     = bee
B/C   = because
C     = sea
D     = dog
D/D   = Dee Dee

(这些字母并不是音符,只是抽象的标记。)

请注意,A开始多个条目,还要注意如何转换C笔画取决于您之前是否看过A、B,或者您正在从头开始。

Also note that (although not shown in the very small sample above), there may be multiple ways to "play" the same word or phrase, rather than just one. Stenographers do that to make it easier to flow from a preceding word to the next depending on hand position. There's an obvious analogy to music there, and you could use that to make your typing flow more akin to playing music, in order to both prevent this from negatively affecting your piano playing and to maximize the likelihood of this actually helping with the RSI.

When translating steno into standard text, again we use a "longest-prefix match" search: The translation algorithm starts with the first stroke ever written, and looks for entries starting with that stroke. If there is only one entry, and it's one stroke long, then we can reliably say "that's the entry to use", output the corresponding text, and then start fresh with the next stroke. But more likely, that stroke starts multiple entries of varying lengths. So we look at the next stroke and see if there are entries that start with those two strokes in order; and so on until we get a match.

根据上面的字典,假设我们看到了这个序列:

A C B B C A B C A B D

我们是这样翻译的:

A is the start of three entries of varying lengths; look at next stroke: C A/C matches only one entry; output "air conditioning" and start fresh with next stroke: B B starts two entries; look at next stroke: B B/B doesn't start anything; take the longest previous match (B) and output that ("bee") Having output B = "bee", we still have a B stroke in our buffer. It starts two entries, so look at the next stroke: C B/C matches one entry; output "because" and start fresh with the next stroke: A A starts three entries; look at the next stroke: B A/B starts two entries; look at the next stroke: C A/B/C only matches one entry; output "alphabetic" and start fresh with the next stroke: A A starts three entries; look at next stroke: B A/B starts two entries; look at next stroke: D A/B/D doesn't match anything, so take the longest previous match (A/B) and use it to output "alphabet". That leaves us with D still in the buffer. D starts two entries, so we would normally look at the next stroke — but we've processed all the strokes, so consider it in isolation. In isolation, it translates as "dog" so output that.

以上各方面要注意:

You have a buffer of strokes you've read but haven't translated yet. You always want to match the most strokes against a single entry that you can. A/B should be translated as "alphabet", not "alpha" and "bee". (Not shown above) You may well have sequences of strokes that you can't translate, because they don't match anything in the dictionary. (Steno people use the noun "untranslate" -- e.g., with our dictionary, the strokes E would be an "untranslate".) (Not shown above) Some theories of steno allow the same set of strokes to mean more than one thing, based on a broader context. Steno people call these "conflicts". You probably want to disallow them in your project, and in fact when steno used to be translated manually by the stenographer, conflicts were fine because they'd know just by where in the sentence they were what the right choice was, but with the rise of machine translation, conflict-free theories of steno arose specifically to avoid having to go through the resulting translated text and "fix" conflicts. Translating in real time (which you'd be doing) means that if you receive a partial match, you'll want to hold onto it while waiting for the next chord — but probably only up to a timeout, at which point you'd translate what you have in the buffer as best you can. (Or maybe you don't want a timeout; it's your call.) Probably best to have a stroke that says "disregard the previous stroke" Probably best to have a stroke that says "completely clear the buffer without outputting anything"