gus_synth.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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(snd_gus_card_t * gus, int client, int port)
  34. {
  35. int idx;
  36. snd_gus_voice_t * 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, snd_seq_port_subscribe_t *info)
  44. {
  45. snd_gus_port_t * port = (snd_gus_port_t *)private_data;
  46. snd_gus_card_t * gus = port->gus;
  47. snd_gus_voice_t * voice;
  48. unsigned int idx;
  49. if (info->voices > 32)
  50. return -EINVAL;
  51. down(&gus->register_mutex);
  52. if (!snd_gus_use_inc(gus)) {
  53. up(&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. up(&gus->register_mutex);
  62. return -EBUSY;
  63. }
  64. voice->index = idx;
  65. }
  66. up(&gus->register_mutex);
  67. return 0;
  68. }
  69. static int snd_gus_synth_unuse(void *private_data, snd_seq_port_subscribe_t *info)
  70. {
  71. snd_gus_port_t * port = (snd_gus_port_t *)private_data;
  72. snd_gus_card_t * gus = port->gus;
  73. down(&gus->register_mutex);
  74. snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
  75. snd_gus_use_dec(gus);
  76. up(&gus->register_mutex);
  77. return 0;
  78. }
  79. /*
  80. *
  81. */
  82. static void snd_gus_synth_free_private_instruments(snd_gus_port_t *p, int client)
  83. {
  84. snd_seq_instr_header_t 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. int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop)
  90. {
  91. snd_gus_port_t * p = (snd_gus_port_t *) private_data;
  92. snd_assert(p != NULL, return -EINVAL);
  93. if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
  94. ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
  95. snd_gus_sample_event(ev, p);
  96. return 0;
  97. }
  98. if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
  99. ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
  100. if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
  101. snd_gus_synth_free_private_instruments(p, ev->data.addr.client);
  102. return 0;
  103. }
  104. }
  105. if (direct) {
  106. if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
  107. snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops,
  108. p->gus->gf1.ilist,
  109. ev,
  110. p->gus->gf1.seq_client,
  111. atomic, hop);
  112. return 0;
  113. }
  114. }
  115. return 0;
  116. }
  117. static void snd_gus_synth_instr_notify(void *private_data,
  118. snd_seq_kinstr_t *instr,
  119. int what)
  120. {
  121. unsigned int idx;
  122. snd_gus_card_t *gus = private_data;
  123. snd_gus_voice_t *pvoice;
  124. unsigned long flags;
  125. spin_lock_irqsave(&gus->event_lock, flags);
  126. for (idx = 0; idx < 32; idx++) {
  127. pvoice = &gus->gf1.voices[idx];
  128. if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
  129. if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
  130. pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY);
  131. } else {
  132. snd_gf1_stop_voice(gus, pvoice->number);
  133. pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
  134. }
  135. }
  136. }
  137. spin_unlock_irqrestore(&gus->event_lock, flags);
  138. }
  139. /*
  140. *
  141. */
  142. static void snd_gus_synth_free_port(void *private_data)
  143. {
  144. snd_gus_port_t * p = (snd_gus_port_t *)private_data;
  145. if (p)
  146. snd_midi_channel_free_set(p->chset);
  147. }
  148. static int snd_gus_synth_create_port(snd_gus_card_t * gus, int idx)
  149. {
  150. snd_gus_port_t * p;
  151. snd_seq_port_callback_t callbacks;
  152. char name[32];
  153. int result;
  154. p = &gus->gf1.seq_ports[idx];
  155. p->chset = snd_midi_channel_alloc_set(16);
  156. if (p->chset == NULL)
  157. return -ENOMEM;
  158. p->chset->private_data = p;
  159. p->gus = gus;
  160. p->client = gus->gf1.seq_client;
  161. memset(&callbacks, 0, sizeof(callbacks));
  162. callbacks.owner = THIS_MODULE;
  163. callbacks.use = snd_gus_synth_use;
  164. callbacks.unuse = snd_gus_synth_unuse;
  165. callbacks.event_input = snd_gus_synth_event_input;
  166. callbacks.private_free = snd_gus_synth_free_port;
  167. callbacks.private_data = p;
  168. sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx);
  169. p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client,
  170. &callbacks,
  171. SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
  172. SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
  173. SNDRV_SEQ_PORT_TYPE_SYNTH,
  174. 16, 0,
  175. name);
  176. if (p->chset->port < 0) {
  177. result = p->chset->port;
  178. snd_gus_synth_free_port(p);
  179. return result;
  180. }
  181. p->port = p->chset->port;
  182. return 0;
  183. }
  184. /*
  185. *
  186. */
  187. static int snd_gus_synth_new_device(snd_seq_device_t *dev)
  188. {
  189. snd_gus_card_t *gus;
  190. int client, i;
  191. snd_seq_client_callback_t callbacks;
  192. snd_seq_client_info_t *cinfo;
  193. snd_seq_port_subscribe_t sub;
  194. snd_iwffff_ops_t *iwops;
  195. snd_gf1_ops_t *gf1ops;
  196. snd_simple_ops_t *simpleops;
  197. gus = *(snd_gus_card_t**)SNDRV_SEQ_DEVICE_ARGPTR(dev);
  198. if (gus == NULL)
  199. return -EINVAL;
  200. init_MUTEX(&gus->register_mutex);
  201. gus->gf1.seq_client = -1;
  202. cinfo = kmalloc(sizeof(*cinfo), GFP_KERNEL);
  203. if (! cinfo)
  204. return -ENOMEM;
  205. /* allocate new client */
  206. memset(&callbacks, 0, sizeof(callbacks));
  207. callbacks.private_data = gus;
  208. callbacks.allow_output = callbacks.allow_input = 1;
  209. client = gus->gf1.seq_client =
  210. snd_seq_create_kernel_client(gus->card, 1, &callbacks);
  211. if (client < 0) {
  212. kfree(cinfo);
  213. return client;
  214. }
  215. /* change name of client */
  216. memset(cinfo, 0, sizeof(*cinfo));
  217. cinfo->client = client;
  218. cinfo->type = KERNEL_CLIENT;
  219. sprintf(cinfo->name, gus->interwave ? "AMD InterWave" : "GF1");
  220. snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, cinfo);
  221. kfree(cinfo);
  222. for (i = 0; i < 4; i++)
  223. snd_gus_synth_create_port(gus, i);
  224. gus->gf1.ilist = snd_seq_instr_list_new();
  225. if (gus->gf1.ilist == NULL) {
  226. snd_seq_delete_kernel_client(client);
  227. gus->gf1.seq_client = -1;
  228. return -ENOMEM;
  229. }
  230. gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
  231. simpleops = &gus->gf1.simple_ops;
  232. snd_seq_simple_init(simpleops, gus, NULL);
  233. simpleops->put_sample = snd_gus_simple_put_sample;
  234. simpleops->get_sample = snd_gus_simple_get_sample;
  235. simpleops->remove_sample = snd_gus_simple_remove_sample;
  236. simpleops->notify = snd_gus_synth_instr_notify;
  237. gf1ops = &gus->gf1.gf1_ops;
  238. snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
  239. gf1ops->put_sample = snd_gus_gf1_put_sample;
  240. gf1ops->get_sample = snd_gus_gf1_get_sample;
  241. gf1ops->remove_sample = snd_gus_gf1_remove_sample;
  242. gf1ops->notify = snd_gus_synth_instr_notify;
  243. iwops = &gus->gf1.iwffff_ops;
  244. snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
  245. iwops->put_sample = snd_gus_iwffff_put_sample;
  246. iwops->get_sample = snd_gus_iwffff_get_sample;
  247. iwops->remove_sample = snd_gus_iwffff_remove_sample;
  248. iwops->notify = snd_gus_synth_instr_notify;
  249. memset(&sub, 0, sizeof(sub));
  250. sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
  251. sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
  252. sub.dest.client = client;
  253. sub.dest.port = 0;
  254. snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
  255. return 0;
  256. }
  257. static int snd_gus_synth_delete_device(snd_seq_device_t *dev)
  258. {
  259. snd_gus_card_t *gus;
  260. gus = *(snd_gus_card_t**)SNDRV_SEQ_DEVICE_ARGPTR(dev);
  261. if (gus == NULL)
  262. return -EINVAL;
  263. if (gus->gf1.seq_client >= 0) {
  264. snd_seq_delete_kernel_client(gus->gf1.seq_client);
  265. gus->gf1.seq_client = -1;
  266. }
  267. if (gus->gf1.ilist)
  268. snd_seq_instr_list_free(&gus->gf1.ilist);
  269. return 0;
  270. }
  271. static int __init alsa_gus_synth_init(void)
  272. {
  273. static snd_seq_dev_ops_t ops = {
  274. snd_gus_synth_new_device,
  275. snd_gus_synth_delete_device
  276. };
  277. return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops,
  278. sizeof(snd_gus_card_t*));
  279. }
  280. static void __exit alsa_gus_synth_exit(void)
  281. {
  282. snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS);
  283. }
  284. module_init(alsa_gus_synth_init)
  285. module_exit(alsa_gus_synth_exit)