diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:44:47 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:12:44 -0400 |
commit | 83d8d72dffa87a6dcecce229617273be62ec5bc0 (patch) | |
tree | 3eb795a28972593f9da2d4f81c05e538553551cb /sound/firewire/amdtp.c | |
parent | 2b3fc456febf540cd9bbf4c8cb4fba0dd0648df3 (diff) |
ALSA: firewire-lib: Add support for MIDI capture/playback
For capturing/playbacking MIDI messages, this commit adds one MIDI conformant
data channel. This data channel has multiplexed 8 MIDI data streams. So this
data channel can transfer messages from/to 8 MIDI ports.
And this commit allows to set PCM format even if AMDTP streams already start.
I suppose the case that PCM substreams are going to be joined into AMDTP
streams when AMDTP streams are already started for MIDI substreams. Each
driver must count how many PCM/MIDI substreams use AMDTP streams to stop
AMDTP streams.
There are differences between specifications about MIDI conformant data.
About the multiplexing, IEC 61883-6:2002, itself, has no information. It
describes labels and bytes for MIDI messages and refers to MMA/AMEI RP-027
for 'successfull implementation'. MMA/AMEI RP-027 describes 8 MPX-MIDI data
streams for one MIDI conformant data channel. IEC 61883-6:2005 adds
'sequence multiplexing' and apply this way and describe incompatibility
between 2002 and 2005.
So this commit applies IEC 61883-6:2005. When we find some devices compliant
to IEC 61883-6:2002, then this difference should be handles as device quirk
in additional work.
About the number of bytes in an MIDI conformant data, IEC 61883-6:2002 describe
0,1,2,3 bytes. MMA/AMEI RP-027 describes 'MIDI1.0-1x-SPEED', 'MIDI1.0-2x-SPEED',
'MIDI1.0-3x-SPEED' modes and the maximum bytes for each mode corresponds to 1,
2, 3 bytes. The 'MIDI1.0-2x/3x-SPEED' modes are accompanied with 'negotiation
procedure' and 'encapsulation details' but there is no specifications for them.
So this commit implements 'MIDI1.0-1x-SPEED' mode for playback, but allows
to pick up 1-3 bytes for capturing.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r-- | sound/firewire/amdtp.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index be1aabcda0d2..a4553ec1b63e 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <sound/pcm.h> | 14 | #include <sound/pcm.h> |
15 | #include <sound/rawmidi.h> | ||
15 | #include "amdtp.h" | 16 | #include "amdtp.h" |
16 | 17 | ||
17 | #define TICKS_PER_CYCLE 3072 | 18 | #define TICKS_PER_CYCLE 3072 |
@@ -123,9 +124,12 @@ void amdtp_stream_set_parameters(struct amdtp_stream *s, | |||
123 | [CIP_SFC_176400] = 176400, | 124 | [CIP_SFC_176400] = 176400, |
124 | [CIP_SFC_192000] = 192000, | 125 | [CIP_SFC_192000] = 192000, |
125 | }; | 126 | }; |
126 | unsigned int sfc; | 127 | unsigned int sfc, midi_channels; |
127 | 128 | ||
128 | if (WARN_ON(amdtp_stream_running(s))) | 129 | midi_channels = DIV_ROUND_UP(midi_ports, 8); |
130 | |||
131 | if (WARN_ON(amdtp_stream_running(s)) || | ||
132 | WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI)) | ||
129 | return; | 133 | return; |
130 | 134 | ||
131 | for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc) | 135 | for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc) |
@@ -142,7 +146,7 @@ sfc_found: | |||
142 | pcm_channels *= 2; | 146 | pcm_channels *= 2; |
143 | } | 147 | } |
144 | s->sfc = sfc; | 148 | s->sfc = sfc; |
145 | s->data_block_quadlets = pcm_channels + DIV_ROUND_UP(midi_ports, 8); | 149 | s->data_block_quadlets = pcm_channels + midi_channels; |
146 | s->pcm_channels = pcm_channels; | 150 | s->pcm_channels = pcm_channels; |
147 | s->midi_ports = midi_ports; | 151 | s->midi_ports = midi_ports; |
148 | 152 | ||
@@ -200,7 +204,7 @@ static void amdtp_read_s32_dualwire(struct amdtp_stream *s, | |||
200 | void amdtp_stream_set_pcm_format(struct amdtp_stream *s, | 204 | void amdtp_stream_set_pcm_format(struct amdtp_stream *s, |
201 | snd_pcm_format_t format) | 205 | snd_pcm_format_t format) |
202 | { | 206 | { |
203 | if (WARN_ON(amdtp_stream_running(s))) | 207 | if (WARN_ON(amdtp_stream_pcm_running(s))) |
204 | return; | 208 | return; |
205 | 209 | ||
206 | switch (format) { | 210 | switch (format) { |
@@ -507,11 +511,41 @@ static void amdtp_fill_pcm_silence(struct amdtp_stream *s, | |||
507 | static void amdtp_fill_midi(struct amdtp_stream *s, | 511 | static void amdtp_fill_midi(struct amdtp_stream *s, |
508 | __be32 *buffer, unsigned int frames) | 512 | __be32 *buffer, unsigned int frames) |
509 | { | 513 | { |
510 | unsigned int i; | 514 | unsigned int f, port; |
515 | u8 *b; | ||
516 | |||
517 | for (f = 0; f < frames; f++) { | ||
518 | buffer[s->pcm_channels + 1] = 0; | ||
519 | b = (u8 *)&buffer[s->pcm_channels + 1]; | ||
520 | |||
521 | port = (s->data_block_counter + f) % 8; | ||
522 | if ((s->midi[port] == NULL) || | ||
523 | (snd_rawmidi_transmit(s->midi[port], b + 1, 1) <= 0)) | ||
524 | b[0] = 0x80; | ||
525 | else | ||
526 | b[0] = 0x81; | ||
527 | |||
528 | buffer += s->data_block_quadlets; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | static void amdtp_pull_midi(struct amdtp_stream *s, | ||
533 | __be32 *buffer, unsigned int frames) | ||
534 | { | ||
535 | unsigned int f, port; | ||
536 | int len; | ||
537 | u8 *b; | ||
538 | |||
539 | for (f = 0; f < frames; f++) { | ||
540 | port = (s->data_block_counter + f) % 8; | ||
541 | b = (u8 *)&buffer[s->pcm_channels + 1]; | ||
511 | 542 | ||
512 | for (i = 0; i < frames; ++i) | 543 | len = b[0] - 0x80; |
513 | buffer[s->pcm_channels + i * s->data_block_quadlets] = | 544 | if ((1 <= len) && (len <= 3) && (s->midi[port])) |
514 | cpu_to_be32(0x80000000); | 545 | snd_rawmidi_receive(s->midi[port], b + 1, len); |
546 | |||
547 | buffer += s->data_block_quadlets; | ||
548 | } | ||
515 | } | 549 | } |
516 | 550 | ||
517 | static void update_pcm_pointers(struct amdtp_stream *s, | 551 | static void update_pcm_pointers(struct amdtp_stream *s, |
@@ -688,6 +722,9 @@ static void handle_in_packet(struct amdtp_stream *s, | |||
688 | pcm = ACCESS_ONCE(s->pcm); | 722 | pcm = ACCESS_ONCE(s->pcm); |
689 | if (pcm) | 723 | if (pcm) |
690 | s->transfer_samples(s, pcm, buffer, data_blocks); | 724 | s->transfer_samples(s, pcm, buffer, data_blocks); |
725 | |||
726 | if (s->midi_ports) | ||
727 | amdtp_pull_midi(s, buffer, data_blocks); | ||
691 | } | 728 | } |
692 | 729 | ||
693 | s->data_block_counter = (data_block_counter + data_blocks) & 0xff; | 730 | s->data_block_counter = (data_block_counter + data_blocks) & 0xff; |