gus_synth.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * Routines for Gravis UltraSound soundcards - Synthesizer
  3. * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  4. *
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. */
  21. #include <sound/driver.h>
  22. #include <linux/init.h>
  23. #include <linux/time.h>
  24. #include <sound/core.h>
  25. #include <sound/gus.h>
  26. #include <sound/seq_device.h>
  27. MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
  28. MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer");
  29. MODULE_LICENSE("GPL");
  30. /*
  31. *
  32. */
  33. static void snd_gus_synth_free_voices(struct snd_gus_card * gus, int client, int port)
  34. {
  35. int idx;
  36. struct snd_gus_voice * voice;
  37. for (idx = 0; idx < 32; idx++) {
  38. voice = &gus->gf1.voices[idx];
  39. if (voice->use && voice->client == client && voice->port == port)
  40. snd_gf1_free_voice(gus, voice);
  41. }
  42. }
  43. static int snd_gus_synth_use(void *private_data, struct snd_seq_port_subscribe *info)
  44. {
  45. struct snd_gus_port * port = private_data;
  46. struct snd_gus_card * gus = port->gus;
  47. struct snd_gus_voice * voice;
  48. unsigned int idx;
  49. if (info->voices > 32)
  50. return -EINVAL;
  51. mutex_lock(&gus->register_mutex);
  52. if (!snd_gus_use_inc(gus)) {
  53. mutex_unlock(&gus->register_mutex);
  54. return -EFAULT;
  55. }
  56. for (idx = 0; idx < info->voices; idx++) {
  57. voice = snd_gf1_alloc_voice(gus, SNDRV_GF1_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
  58. if (voice == NULL) {
  59. snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
  60. snd_gus_use_dec(gus);
  61. mutex_unlock(&gus->register_mutex);
  62. return -EBUSY;
  63. }
  64. voice->index = idx;
  65. }
  66. mutex_unlock(&gus->register_mutex);
  67. return 0;
  68. }
  69. static int snd_gus_synth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
  70. {
  71. struct snd_gus_port * port = private_data;
  72. struct snd_gus_card * gus = port->gus;
  73. mutex_lock(&gus->register_mutex);
  74. snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
  75. snd_gus_use_dec(gus);
  76. mutex_unlock(&gus->register_mutex);
  77. return 0;
  78. }
  79. /*
  80. *
  81. */
  82. static void snd_gus_synth_free_private_instruments(struct snd_gus_port *p, int client)
  83. {
  84. struct snd_seq_instr_header ifree;
  85. memset(&ifree, 0, sizeof(ifree));
  86. ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
  87. snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0);
  88. }
  89. static int snd_gus_synth_event_input(struct snd_seq_event *ev, int direct,
  90. void *private_data, int atomic, int hop)
  91. {
  92. struct snd_gus_port * p = private_data;
  93. snd_assert(p != NULL, return -EINVAL);
  94. if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
  95. ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
  96. snd_gus_sample_event(ev, p);
  97. return 0;
  98. }
  99. if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
  100. ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
  101. if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
  102. snd_gus_synth_free_private_instruments(p, ev->data.addr.client);
  103. return 0;
  104. }
  105. }
  106. if (direct) {
  107. if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
  108. snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops,
  109. p->gus->gf1.ilist,
  110. ev,
  111. p->gus->gf1.seq_client,
  112. atomic, hop);
  113. return 0;
  114. }
  115. }
  116. return 0;
  117. }
  118. static void snd_gus_synth_instr_notify(void *private_data,
  119. struct snd_seq_kinstr *instr,
  120. int what)
  121. {
  122. unsigned int idx;
  123. struct snd_gus_card *gus = private_data;
  124. struct snd_gus_voice *pvoice;
  125. unsigned long flags;
  126. spin_lock_irqsave(&gus->event_lock, flags);
  127. for (idx = 0; idx < 32; idx++) {
  128. pvoice = &gus->gf1.voices[idx];
  129. if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
  130. if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
  131. pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY);
  132. } else {
  133. snd_gf1_stop_voice(gus, pvoice->number);
  134. pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
  135. }
  136. }
  137. }
  138. spin_unlock_irqrestore(&gus->event_lock, flags);
  139. }
  140. /*
  141. *
  142. */
  143. static void snd_gus_synth_free_port(void *private_data)
  144. {
  145. struct snd_gus_port * p = private_data;
  146. if (p)
  147. snd_midi_channel_free_set(p->chset);
  148. }
  149. static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx)
  150. {
  151. struct snd_gus_port * p;
  152. struct snd_seq_port_callback callbacks;
  153. char name[32];
  154. int result;
  155. p = &gus->gf1.seq_ports[idx];
  156. p->chset = snd_midi_channel_alloc_set(16);
  157. if (p->chset == NULL)
  158. return -ENOMEM;
  159. p->chset->private_data = p;
  160. p->gus = gus;
  161. p->client = gus->gf1.seq_client;
  162. memset(&callbacks, 0, sizeof(callbacks));
  163. callbacks.owner = THIS_MODULE;
  164. callbacks.use = snd_gus_synth_use;
  165. callbacks.unuse = snd_gus_synth_unuse;
  166. callbacks.event_input = snd_gus_synth_event_input;
  167. callbacks.private_free = snd_gus_synth_free_port;
  168. callbacks.private_data = p;
  169. sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx);
  170. p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client,
  171. &callbacks,
  172. SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
  173. SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
  174. SNDRV_SEQ_PORT_TYPE_SYNTH |
  175. SNDRV_SEQ_PORT_TYPE_HARDWARE |
  176. SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
  177. 16, 0,
  178. name);
  179. if (p->chset->port < 0) {
  180. result = p->chset->port;
  181. snd_gus_synth_free_port(p);
  182. return result;
  183. }
  184. p->port = p->chset->port;
  185. return 0;
  186. }
  187. /*
  188. *
  189. */
  190. static int snd_gus_synth_new_device(struct snd_seq_device *dev)
  191. {
  192. struct snd_gus_card *gus;
  193. int client, i;
  194. struct snd_seq_port_subscribe sub;
  195. struct snd_iwffff_ops *iwops;
  196. struct snd_gf1_ops *gf1ops;
  197. struct snd_simple_ops *simpleops;
  198. gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
  199. if (gus == NULL)
  200. return -EINVAL;
  201. mutex_init(&gus->register_mutex);
  202. gus->gf1.seq_client = -1;
  203. /* allocate new client */
  204. client = gus->gf1.seq_client =
  205. snd_seq_create_kernel_client(gus->card, 1, gus->interwave ?
  206. "AMD InterWave" : "GF1");
  207. if (client < 0)
  208. return client;
  209. for (i = 0; i < 4; i++)
  210. snd_gus_synth_create_port(gus, i);
  211. gus->gf1.ilist = snd_seq_instr_list_new();
  212. if (gus->gf1.ilist == NULL) {
  213. snd_seq_delete_kernel_client(client);
  214. gus->gf1.seq_client = -1;
  215. return -ENOMEM;
  216. }
  217. gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
  218. simpleops = &gus->gf1.simple_ops;
  219. snd_seq_simple_init(simpleops, gus, NULL);
  220. simpleops->put_sample = snd_gus_simple_put_sample;
  221. simpleops->get_sample = snd_gus_simple_get_sample;
  222. simpleops->remove_sample = snd_gus_simple_remove_sample;
  223. simpleops->notify = snd_gus_synth_instr_notify;
  224. gf1ops = &gus->gf1.gf1_ops;
  225. snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
  226. gf1ops->put_sample = snd_gus_gf1_put_sample;
  227. gf1ops->get_sample = snd_gus_gf1_get_sample;
  228. gf1ops->remove_sample = snd_gus_gf1_remove_sample;
  229. gf1ops->notify = snd_gus_synth_instr_notify;
  230. iwops = &gus->gf1.iwffff_ops;
  231. snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
  232. iwops->put_sample = snd_gus_iwffff_put_sample;
  233. iwops->get_sample = snd_gus_iwffff_get_sample;
  234. iwops->remove_sample = snd_gus_iwffff_remove_sample;
  235. iwops->notify = snd_gus_synth_instr_notify;
  236. memset(&sub, 0, sizeof(sub));
  237. sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
  238. sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
  239. sub.dest.client = client;
  240. sub.dest.port = 0;
  241. snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
  242. return 0;
  243. }
  244. static int snd_gus_synth_delete_device(struct snd_seq_device *dev)
  245. {
  246. struct snd_gus_card *gus;
  247. gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
  248. if (gus == NULL)
  249. return -EINVAL;
  250. if (gus->gf1.seq_client >= 0) {
  251. snd_seq_delete_kernel_client(gus->gf1.seq_client);
  252. gus->gf1.seq_client = -1;
  253. }
  254. if (gus->gf1.ilist)
  255. snd_seq_instr_list_free(&gus->gf1.ilist);
  256. return 0;
  257. }
  258. static int __init alsa_gus_synth_init(void)
  259. {
  260. static struct snd_seq_dev_ops ops = {
  261. snd_gus_synth_new_device,
  262. snd_gus_synth_delete_device
  263. };
  264. return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops,
  265. sizeof(struct snd_gus_card *));
  266. }
  267. static void __exit alsa_gus_synth_exit(void)
  268. {
  269. snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS);
  270. }
  271. module_init(alsa_gus_synth_init)
  272. module_exit(alsa_gus_synth_exit)