1/* 2 * Routines for Gravis UltraSound soundcards - Simple instrument handlers 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 22#include <sound/driver.h> 23#include <linux/time.h> 24#include <sound/core.h> 25#include <sound/gus.h> 26#include "gus_tables.h" 27 28/* 29 * 30 */ 31 32static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice); 33static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice); 34static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice); 35 36static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position); 37static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode); 38static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq); 39static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume); 40static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop); 41static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position); 42static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data); 43 44static struct snd_gus_sample_ops sample_ops = { 45 sample_start, 46 sample_stop, 47 sample_freq, 48 sample_volume, 49 sample_loop, 50 sample_pos, 51 sample_private1 52}; 53 54 55static void do_volume_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice); 56static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice); 57 58/* 59 * 60 */ 61 62static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice) 63{ 64 spin_lock(&gus->event_lock); 65 snd_gf1_stop_voice(gus, voice->number); 66 spin_lock(&gus->reg_lock); 67 snd_gf1_select_voice(gus, voice->number); 68 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0); 69 spin_unlock(&gus->reg_lock); 70 voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; 71 spin_unlock(&gus->event_lock); 72} 73 74static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice) 75{ 76 spin_lock(&gus->event_lock); 77 if (voice->flags & SNDRV_GF1_VFLG_RUNNING) 78 do_volume_envelope(gus, voice); 79 else 80 snd_gf1_stop_voice(gus, voice->number); 81 spin_unlock(&gus->event_lock); 82} 83 84static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice) 85{ 86 spin_lock(&gus->event_lock); 87 if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) == 88 (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) 89 do_pan_envelope(gus, voice); 90 spin_unlock(&gus->event_lock); 91} 92 93/* 94 * 95 */ 96 97static void do_volume_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice) 98{ 99 unsigned short next, rate, old_volume; 100 int program_next_ramp; 101 unsigned long flags; 102 103 if (!gus->gf1.volume_ramp) { 104 spin_lock_irqsave(&gus->reg_lock, flags); 105 snd_gf1_select_voice(gus, voice->number); 106 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); 107 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume); 108 /* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */ 109 spin_unlock_irqrestore(&gus->reg_lock, flags); 110 return; 111 } 112 program_next_ramp = 0; 113 rate = next = 0; 114 while (1) { 115 program_next_ramp = 0; 116 rate = next = 0; 117 switch (voice->venv_state) { 118 case VENV_BEFORE: 119 voice->venv_state = VENV_ATTACK; 120 voice->venv_value_next = 0; 121 spin_lock_irqsave(&gus->reg_lock, flags); 122 snd_gf1_select_voice(gus, voice->number); 123 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); 124 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME); 125 spin_unlock_irqrestore(&gus->reg_lock, flags); 126 break; 127 case VENV_ATTACK: 128 voice->venv_state = VENV_SUSTAIN; 129 program_next_ramp++; 130 next = 255; 131 rate = gus->gf1.volume_ramp; 132 break; 133 case VENV_SUSTAIN: 134 voice->venv_state = VENV_RELEASE; 135 spin_lock_irqsave(&gus->reg_lock, flags); 136 snd_gf1_select_voice(gus, voice->number); 137 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); 138 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255); 139 spin_unlock_irqrestore(&gus->reg_lock, flags); 140 return; 141 case VENV_RELEASE: 142 voice->venv_state = VENV_DONE; 143 program_next_ramp++; 144 next = 0; 145 rate = gus->gf1.volume_ramp; 146 break; 147 case VENV_DONE: 148 snd_gf1_stop_voice(gus, voice->number); 149 voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; 150 return; 151 case VENV_VOLUME: 152 program_next_ramp++; 153 next = voice->venv_value_next; 154 rate = gus->gf1.volume_ramp; 155 voice->venv_state = voice->venv_state_prev; 156 break; 157 } 158 voice->venv_value_next = next; 159 if (!program_next_ramp) 160 continue; 161 spin_lock_irqsave(&gus->reg_lock, flags); 162 snd_gf1_select_voice(gus, voice->number); 163 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); 164 old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8; 165 if (!rate) { 166 spin_unlock_irqrestore(&gus->reg_lock, flags); 167 continue; 168 } 169 next = (((int)voice->gf1_volume * (int)next) / 255) >> 8; 170 if (old_volume < SNDRV_GF1_MIN_OFFSET) 171 old_volume = SNDRV_GF1_MIN_OFFSET; 172 if (next < SNDRV_GF1_MIN_OFFSET) 173 next = SNDRV_GF1_MIN_OFFSET; 174 if (next > SNDRV_GF1_MAX_OFFSET) 175 next = SNDRV_GF1_MAX_OFFSET; 176 if (old_volume == next) { 177 spin_unlock_irqrestore(&gus->reg_lock, flags); 178 continue; 179 } 180 voice->volume_control &= ~0xc3; 181 voice->volume_control |= 0x20; 182 if (old_volume > next) { 183 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next); 184 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume); 185 voice->volume_control |= 0x40; 186 } else { 187 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume); 188 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next); 189 } 190 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate); 191 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control); 192 if (!gus->gf1.enh_mode) { 193 snd_gf1_delay(gus); 194 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control); 195 } 196 spin_unlock_irqrestore(&gus->reg_lock, flags); 197 return; 198 } 199} 200 201static void do_pan_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice) 202{ 203 unsigned long flags; 204 unsigned char old_pan; 205 206 if (gus->gf1.enh_mode) { 207 voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN); 208 return; 209 } 210 if (!gus->gf1.smooth_pan) { 211 spin_lock_irqsave(&gus->reg_lock, flags); 212 snd_gf1_select_voice(gus, voice->number); 213 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan); 214 spin_unlock_irqrestore(&gus->reg_lock, flags); 215 return; 216 } 217 if (!(voice->flags & SNDRV_GF1_VFLG_PAN)) /* before */ 218 voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN; 219 spin_lock_irqsave(&gus->reg_lock, flags); 220 snd_gf1_select_voice(gus, voice->number); 221 old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f; 222 if (old_pan > voice->gf1_pan ) 223 old_pan--; 224 if (old_pan < voice->gf1_pan) 225 old_pan++; 226 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan); 227 spin_unlock_irqrestore(&gus->reg_lock, flags); 228 if (old_pan == voice->gf1_pan) /* the goal was reached */ 229 voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN); 230} 231 232static void set_enhanced_pan(struct snd_gus_card *gus, struct snd_gus_voice *voice, unsigned short pan) 233{ 234 unsigned long flags; 235 unsigned short vlo, vro; 236 237 vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan); 238 vro = SNDRV_GF1_ATTEN(pan); 239 if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) { 240 vlo >>= 1; 241 vro >>= 1; 242 } 243 vlo <<= 4; 244 vro <<= 4; 245 spin_lock_irqsave(&gus->reg_lock, flags); 246 snd_gf1_select_voice(gus, voice->number); 247 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo); 248 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro); 249 spin_unlock_irqrestore(&gus->reg_lock, flags); 250 voice->vlo = vlo; 251 voice->vro = vro; 252} 253 254/* 255 * 256 */ 257 258static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position) 259{ 260 unsigned long flags; 261 unsigned int begin, addr, addr_end, addr_start; 262 int w_16; 263 struct simple_instrument *simple; 264 struct snd_seq_kinstr *instr; 265 266 instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); 267 if (instr == NULL) 268 return; 269 voice->instr = instr->instr; /* copy ID to speedup aliases */ 270 simple = KINSTR_DATA(instr); 271 begin = simple->address.memory << 4; 272 w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0; 273 addr_start = simple->loop_start; 274 if (simple->format & SIMPLE_WAVE_LOOP) { 275 addr_end = simple->loop_end; 276 } else { 277 addr_end = (simple->size << 4) - (w_16 ? 40 : 24); 278 } 279 if (simple->format & SIMPLE_WAVE_BACKWARD) { 280 addr = simple->loop_end; 281 if (position < simple->loop_end) 282 addr -= position; 283 } else { 284 addr = position; 285 } 286 voice->control = 0x00; 287 voice->mode = 0x20; /* enable offset registers */ 288 if (simple->format & SIMPLE_WAVE_16BIT) 289 voice->control |= 0x04; 290 if (simple->format & SIMPLE_WAVE_BACKWARD) 291 voice->control |= 0x40; 292 if (simple->format & SIMPLE_WAVE_LOOP) { 293 voice->control |= 0x08; 294 } else { 295 voice->control |= 0x20; 296 } 297 if (simple->format & SIMPLE_WAVE_BIDIR) 298 voice->control |= 0x10; 299 if (simple->format & SIMPLE_WAVE_ULAW) 300 voice->mode |= 0x40; 301 if (w_16) { 302 addr = ((addr << 1) & ~0x1f) | (addr & 0x0f); 303 addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f); 304 addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f); 305 } 306 addr += begin; 307 addr_start += begin; 308 addr_end += begin; 309 snd_gf1_stop_voice(gus, voice->number); 310 spin_lock_irqsave(&gus->reg_lock, flags); 311 snd_gf1_select_voice(gus, voice->number); 312 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo); 313 voice->venv_state = VENV_BEFORE; 314 voice->volume_control = 0x03; 315 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16); 316 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16); 317 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16); 318 if (!gus->gf1.enh_mode) { 319 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan); 320 } else { 321 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo); 322 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo); 323 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro); 324 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro); 325 snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator); 326 snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume); 327 snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume); 328 } 329 spin_unlock_irqrestore(&gus->reg_lock, flags); 330 do_volume_envelope(gus, voice); 331 spin_lock_irqsave(&gus->reg_lock, flags); 332 snd_gf1_select_voice(gus, voice->number); 333 if (gus->gf1.enh_mode) 334 snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode); 335 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control); 336 if (!gus->gf1.enh_mode) { 337 snd_gf1_delay(gus); 338 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control ); 339 } 340 spin_unlock_irqrestore(&gus->reg_lock, flags); 341 voice->flags |= SNDRV_GF1_VFLG_RUNNING; 342 snd_seq_instr_free_use(gus->gf1.ilist, instr); 343} 344 345static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode) 346{ 347 unsigned char control; 348 unsigned long flags; 349 350 if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING)) 351 return; 352 switch (mode) { 353 default: 354 if (gus->gf1.volume_ramp > 0) { 355 if (voice->venv_state < VENV_RELEASE) { 356 voice->venv_state = VENV_RELEASE; 357 do_volume_envelope(gus, voice); 358 } 359 } 360 if (mode != SAMPLE_STOP_VENVELOPE) { 361 snd_gf1_stop_voice(gus, voice->number); 362 spin_lock_irqsave(&gus->reg_lock, flags); 363 snd_gf1_select_voice(gus, voice->number); 364 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME); 365 spin_unlock_irqrestore(&gus->reg_lock, flags); 366 voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; 367 } 368 break; 369 case SAMPLE_STOP_LOOP: /* disable loop only */ 370 spin_lock_irqsave(&gus->reg_lock, flags); 371 snd_gf1_select_voice(gus, voice->number); 372 control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); 373 control &= ~(0x83 | 0x04); 374 control |= 0x20; 375 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control); 376 spin_unlock_irqrestore(&gus->reg_lock, flags); 377 break; 378 } 379} 380 381static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq) 382{ 383 unsigned long flags; 384 385 spin_lock_irqsave(&gus->reg_lock, flags); 386 voice->fc_register = snd_gf1_translate_freq(gus, freq); 387 snd_gf1_select_voice(gus, voice->number); 388 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo); 389 spin_unlock_irqrestore(&gus->reg_lock, flags); 390} 391 392static void sample_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume) 393{ 394 if (volume->volume >= 0) { 395 volume->volume &= 0x3fff; 396 voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4; 397 voice->venv_state_prev = VENV_SUSTAIN; 398 voice->venv_state = VENV_VOLUME; 399 do_volume_envelope(gus, voice); 400 } 401 if (volume->lr >= 0) { 402 volume->lr &= 0x3fff; 403 if (!gus->gf1.enh_mode) { 404 voice->gf1_pan = (volume->lr >> 10) & 15; 405 if (!gus->gf1.full_range_pan) { 406 if (voice->gf1_pan == 0) 407 voice->gf1_pan++; 408 if (voice->gf1_pan == 15) 409 voice->gf1_pan--; 410 } 411 voice->flags &= ~SNDRV_GF1_VFLG_PAN; /* before */ 412 do_pan_envelope(gus, voice); 413 } else { 414 set_enhanced_pan(gus, voice, volume->lr >> 7); 415 } 416 } 417} 418 419static void sample_loop(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop) 420{ 421 unsigned long flags; 422 int w_16 = voice->control & 0x04; 423 unsigned int begin, addr_start, addr_end; 424 struct simple_instrument *simple; 425 struct snd_seq_kinstr *instr; 426 427 instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); 428 if (instr == NULL) 429 return; 430 voice->instr = instr->instr; /* copy ID to speedup aliases */ 431 simple = KINSTR_DATA(instr); 432 begin = simple->address.memory; 433 addr_start = loop->start; 434 addr_end = loop->end; 435 addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin; 436 addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin; 437 spin_lock_irqsave(&gus->reg_lock, flags); 438 snd_gf1_select_voice(gus, voice->number); 439 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16); 440 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16); 441 spin_unlock_irqrestore(&gus->reg_lock, flags); 442 snd_seq_instr_free_use(gus->gf1.ilist, instr); 443} 444 445static void sample_pos(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position) 446{ 447 unsigned long flags; 448 int w_16 = voice->control & 0x04; 449 unsigned int begin, addr; 450 struct simple_instrument *simple; 451 struct snd_seq_kinstr *instr; 452 453 instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); 454 if (instr == NULL) 455 return; 456 voice->instr = instr->instr; /* copy ID to speedup aliases */ 457 simple = KINSTR_DATA(instr); 458 begin = simple->address.memory; 459 addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin; 460 spin_lock_irqsave(&gus->reg_lock, flags); 461 snd_gf1_select_voice(gus, voice->number); 462 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16); 463 spin_unlock_irqrestore(&gus->reg_lock, flags); 464 snd_seq_instr_free_use(gus->gf1.ilist, instr); 465} 466 467 468static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data) 469{ 470} 471 472 473void snd_gf1_simple_init(struct snd_gus_voice *voice) 474{ 475 voice->handler_wave = interrupt_wave; 476 voice->handler_volume = interrupt_volume; 477 voice->handler_effect = interrupt_effect; 478 voice->volume_change = NULL; 479 voice->sample_ops = &sample_ops; 480} 481