📄 awe_wave.c
字号:
rec->instr = instr; if (i < nvoices - 1) rec->next_instr = rec + 1; else rec->next_instr = curp; rec->next_bank = NULL; /* copy awe_voice_info parameters */ COPY_FROM_USER(&rec->v, addr, offset, sizeof(awe_voice_info)); offset += sizeof(awe_voice_info); rec->v.sf_id = current_sf_id; if (rec->v.mode & AWE_MODE_INIT_PARM) awe_init_voice_parm(&rec->v.parm); awe_set_sample(&rec->v); } /* prepend to top of the list */ infos[free_info].next_bank = preset_table[instr]; preset_table[instr] = &infos[free_info]; free_info += nvoices; return 0;}/* load wave sample data */static intawe_load_data(awe_patch_info *patch, const char *addr){ long offset; int size; int rc; if (free_sample >= AWE_MAX_SAMPLES) { ERRMSG(printk("AWE32 Error: Sample table full\n")); return RET_ERROR(ENOSPC); } size = (patch->len - sizeof(awe_sample_info)) / 2; offset = sizeof(awe_patch_info); COPY_FROM_USER(&samples[free_sample], addr, offset, sizeof(awe_sample_info)); offset += sizeof(awe_sample_info); if (size != samples[free_sample].size) { ERRMSG(printk("AWE32 Warning: sample size differed (%d != %d)\n", (int)samples[free_sample].size, (int)size)); samples[free_sample].size = size; } if (samples[free_sample].size > 0) if ((rc = awe_write_wave_data(addr, offset, size)) != 0) return rc; awe_check_loaded(); samples[free_sample].sf_id = current_sf_id; free_sample++; return 0;}/* check the other samples are already loaded */static voidawe_check_loaded(void){ if (!loaded_once) { /* it's the first time */ last_sample = free_sample; last_info = free_info; current_sf_id++; loaded_once = 1; }}/*----------------------------------------------------------------*/static const char *readbuf_addr;static long readbuf_offs;static int readbuf_flags;#ifdef AWE_USE_BUFFERED_IO#define TMP_WAVBUF_SIZE 4096static unsigned short readbuf[TMP_WAVBUF_SIZE];static int readbuf_size, readbuf_cur, readbuf_left;/* read through temporary buffer */static unsigned shortawe_readbuf_word(int pos){ if (readbuf_left <= 0) { int i; if (readbuf_size - pos < TMP_WAVBUF_SIZE) readbuf_left = readbuf_size - pos; else readbuf_left = TMP_WAVBUF_SIZE; /* read from user buffer */ if (readbuf_flags & AWE_SAMPLE_8BITS) { unsigned char *pbuf = (unsigned char *)readbuf; COPY_FROM_USER(pbuf, readbuf_addr, readbuf_offs + pos, readbuf_left); /* convert 8bit -> 16bit */ for (i = readbuf_left - 1; i >= 0; i--) readbuf[i] = pbuf[i] << 8; } else { COPY_FROM_USER(readbuf, readbuf_addr, readbuf_offs + pos * 2, readbuf_left*2); } if (readbuf_flags & AWE_SAMPLE_UNSIGNED) { /* unsigned -> signed */ for (i = 0; i < readbuf_left; i++) readbuf[i] ^= 0x8000; } readbuf_cur = 0; } readbuf_left--; return readbuf[readbuf_cur++];}#else /* AWE_USE_BUFFERED_IO */#define awe_readbuf_word(pos) awe_read_word(pos)#endif /* AWE_USE_BUFFERED_IO *//* initialize read buffer */static voidawe_init_readbuf(const char *addr, long offset, int size, int mode_flags){ readbuf_addr = addr; readbuf_offs = offset; readbuf_flags = mode_flags;#ifdef AWE_USE_BUFFERED_IO readbuf_size = size; readbuf_left = 0; readbuf_cur = 0;#endif}/* read directly from user buffer */static unsigned shortawe_read_word(int pos){ unsigned short c; /* read from user buffer */ if (readbuf_flags & AWE_SAMPLE_8BITS) { unsigned char cc; GET_BYTE_FROM_USER(cc, readbuf_addr, readbuf_offs + pos); c = cc << 8; /* convert 8bit -> 16bit */ } else { GET_SHORT_FROM_USER(c, readbuf_addr, readbuf_offs + pos * 2); } if (readbuf_flags & AWE_SAMPLE_UNSIGNED) c ^= 0x8000; /* unsigned -> signed */ return c;}#define BLANK_LOOP_START 8#define BLANK_LOOP_END 40#define BLANK_LOOP_SIZE 48/* loading onto memory */static int awe_write_wave_data(const char *addr, long offset, int size){ awe_sample_info *sp = &samples[free_sample]; int i, truesize; int rc; unsigned long csum1, csum2; DECL_INTR_FLAGS(flags); /* be sure loop points start < end */ if (sp->loopstart > sp->loopend) { long tmp = sp->loopstart; sp->loopstart = sp->loopend; sp->loopend = tmp; } /* compute true data size to be loaded */ truesize = size; if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) truesize += sp->loopend - sp->loopstart; if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) truesize += BLANK_LOOP_SIZE; if (size > 0 && free_mem_ptr + truesize >= awe_mem_size/2) { ERRMSG(printk("AWE32 Error: Sample memory full\n")); return RET_ERROR(ENOSPC); } /* recalculate address offset */ sp->end -= sp->start; sp->loopstart -= sp->start; sp->loopend -= sp->start; sp->size = truesize; sp->start = free_mem_ptr + AWE_DRAM_OFFSET; sp->end += free_mem_ptr + AWE_DRAM_OFFSET; sp->loopstart += free_mem_ptr + AWE_DRAM_OFFSET; sp->loopend += free_mem_ptr + AWE_DRAM_OFFSET; DISABLE_INTR(flags); if ((rc = awe_open_dram_for_write(free_mem_ptr)) != 0) { RESTORE_INTR(flags); return rc; } awe_init_readbuf(addr, offset, size, sp->mode_flags); csum1 = 0; for (i = 0; i < size; i++) { unsigned short c; c = awe_readbuf_word(i); csum1 += c; awe_write_dram(c); if (i == sp->loopend && (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)) { int looplen = sp->loopend - sp->loopstart; /* copy reverse loop */ int k; for (k = 0; k < looplen; k++) { /* non-buffered data */ c = awe_read_word(i - k); awe_write_dram(c); } } } /* if no blank loop is attached in the sample, add it */ if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) { for (i = 0; i < BLANK_LOOP_SIZE; i++) awe_write_dram(0); if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) { sp->loopstart = sp->end + BLANK_LOOP_START; sp->loopend = sp->end + BLANK_LOOP_END; } sp->size += BLANK_LOOP_SIZE; } awe_close_dram(); RESTORE_INTR(flags); if (sp->checksum_flag) {#ifdef AWE_CHECKSUM_DATA if (sp->checksum_flag != 2 && csum1 != sp->checksum) { ERRMSG(printk("AWE32: [%d] checksum mismatch on data %x:%x\n", free_sample, (int)samples[free_sample].checksum, (int)csum1)); return RET_ERROR(NO_DATA_ERR); }#endif /* AWE_CHECKSUM_DATA */#ifdef AWE_CHECKSUM_MEMORY DISABLE_INTR(flags); if (awe_open_dram_for_read(free_mem_ptr) == 0) { csum2 = 0; for (i = 0; i < size; i++) { unsigned short c; c = awe_peek(AWE_SMLD); csum2 += c; } awe_close_dram_for_read(); if (csum2 != samples[free_sample].checksum) { RESTORE_INTR(flags); ERRMSG(printk("AWE32: [%d] checksum mismatch on DRAM %x:%x\n", free_sample, (int)samples[free_sample].checksum, (int)csum2)); return RET_ERROR(NO_DATA_ERR); } } RESTORE_INTR(flags);#endif /* AWE_CHECKSUM_MEMORY */ } free_mem_ptr += sp->size; /* re-initialize FM passthrough */ DISABLE_INTR(flags); awe_init_fm(); awe_tweak(); RESTORE_INTR(flags); return 0;}/* calculate GUS envelope time: * is this correct? i have no idea.. */static intcalc_gus_envelope_time(int rate, int start, int end){ int r, p, t; r = (3 - ((rate >> 6) & 3)) * 3; p = rate & 0x3f; t = end - start; if (t < 0) t = -t; if (13 > r) t = t << (13 - r); else t = t >> (r - 13); return (t * 10) / (p * 441);}#define calc_gus_sustain(val) (0x7f - vol_table[(val)/2])#define calc_gus_attenuation(val) vol_table[(val)/2]/* load GUS patch */static intawe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag){ struct patch_info patch; awe_voice_list *rec, *curp; long sizeof_patch; int note; int rc; sizeof_patch = (long)&patch.data[0] - (long)&patch; /* header size */ if (free_sample >= AWE_MAX_SAMPLES) { ERRMSG(printk("AWE32 Error: Sample table full\n")); return RET_ERROR(ENOSPC); } if (free_info >= AWE_MAX_INFOS) { ERRMSG(printk("AWE32 Error: Too many voice informations\n")); return RET_ERROR(ENOSPC); } if (size < sizeof_patch) { ERRMSG(printk("AWE32 Error: Patch header too short\n")); return RET_ERROR(EINVAL); } COPY_FROM_USER(((char*)&patch) + offs, addr, offs, sizeof_patch - offs); size -= sizeof_patch; if (size < patch.len) { FATALERR(printk("AWE32 Warning: Patch record too short (%d<%d)\n", size, (int)patch.len)); patch.len = size; } samples[free_sample].sf_id = 0; samples[free_sample].sample = free_sample; samples[free_sample].start = 0; samples[free_sample].end = patch.len; samples[free_sample].loopstart = patch.loop_start; samples[free_sample].loopend = patch.loop_end; samples[free_sample].size = patch.len; /* set up mode flags */ samples[free_sample].mode_flags = 0; if (!(patch.mode & WAVE_16_BITS)) samples[free_sample].mode_flags |= AWE_SAMPLE_8BITS; if (patch.mode & WAVE_UNSIGNED) samples[free_sample].mode_flags |= AWE_SAMPLE_UNSIGNED; samples[free_sample].mode_flags |= AWE_SAMPLE_NO_BLANK; if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP))) samples[free_sample].mode_flags |= AWE_SAMPLE_SINGLESHOT; if (patch.mode & WAVE_BIDIR_LOOP) samples[free_sample].mode_flags |= AWE_SAMPLE_BIDIR_LOOP; DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, samples[free_sample].mode_flags)); if (patch.mode & WAVE_16_BITS) { /* convert to word offsets */ samples[free_sample].size /= 2; samples[free_sample].end /= 2; samples[free_sample].loopstart /= 2; samples[free_sample].loopend /= 2; } samples[free_sample].checksum_flag = 0; samples[free_sample].checksum = 0; if ((rc = awe_write_wave_data(addr, sizeof_patch, samples[free_sample].size)) != 0) return rc; awe_check_loaded(); samples[free_sample].sf_id = current_sf_id; free_sample++; /* set up voice info */ rec = &infos[free_info]; awe_init_voice_info(&rec->v); rec->v.sf_id = current_sf_id; rec->v.sample = free_sample - 1; /* the last sample */ rec->v.rate_offset = calc_rate_offset(patch.base_freq); note = freq_to_note(patch.base_note); rec->v.root = note / 100; rec->v.tune = -(note % 100); rec->v.low = freq_to_note(patch.low_note) / 100; rec->v.high = freq_to_note(patch.high_note) / 100; DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n", rec->v.rate_offset, note, rec->v.low, rec->v.high, patch.low_note, patch.high_note)); /* panning position; -128 - 127 => 0-127 */ rec->v.pan = (patch.panning + 128) / 2; /* detuning is ignored */ /* 6points volume envelope */ if (patch.mode & WAVE_ENVELOPES) { int attack, hold, decay, release; attack = calc_gus_envelope_time (patch.env_rate[0], 0, patch.env_offset[0]); hold = calc_gus_envelope_time (patch.env_rate[1], patch.env_offset[0], patch.env_offset[1]); decay = calc_gus_envelope_time (patch.env_rate[2], patch.env_offset[1], patch.env_offset[2]); release = calc_gus_envelope_time (patch.env_rate[3], patch.env_offset[1], patch.env_offset[4]); release += calc_gus_envelope_time (patch.env_rate[4], patch.env_offset[3], patch.env_offset[4]); release += calc_gus_envelope_time (patch.env_rate[5], patch.env_offset[4], patch.env_offset[5]); rec->v.parm.volatkhld = (calc_parm_attack(attack) << 8) | calc_parm_hold(hold); rec->v.parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | calc_parm_decay(decay); rec->v.parm.volrelease = 0x8000 | calc_parm_decay(release); DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release)); rec->v.attenuation = calc_gus_attenuation(patch.env_offset[0]); } /* tremolo effect */ if (patch.mode & WAVE_TREMOLO) { int rate = (patch.tremolo_rate * 1000 / 38) / 42; rec->v.parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate; DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n", patch.tremolo_rate, patch.tremolo_depth, rec->v.parm.tremfrq)); } /* vibrato effect */ if (patch.mode & WAVE_VIBRATO) { int rate = (patch.vibrato_rate * 1000 / 38) / 42; rec->v.parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate; DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n", patch.tremolo_rate, patch.tremolo_depth, rec->v.parm.tremfrq)); } /* scale_freq, scale_factor, volume, and fractions not implemented */ /* set the voice index */ awe_set_sample(&rec->v); /* prepend to top of the list */ curp = awe_search_instr(awe_gus_bank, patch.instr_no); rec->bank = awe_gus_bank; rec->instr = patch.instr_no; rec->next_instr = curp; rec->next_bank = preset_table[rec->instr]; preset_table[rec->instr] = rec; free_info++; return 0;}/* remove samples with current sf_id from instrument list */static awe_voice_list *awe_get_removed_list(awe_voice_list *curp){ awe_voice_list *lastp, **prevp; int maxc; lastp = curp; prevp = &lastp; for (maxc = AWE_MAX_INFOS; curp && maxc; curp = curp->next_instr, maxc--) { if (curp->v.sf_id == current_sf_id) *prevp = curp->next_instr; else prevp = &curp->next_instr; } return lastp;}/* remove last loaded samples */static voidawe_remove_samples(void){ awe_voice_list **prevp, *p, *nextp; int maxc; int i; if (last_sample == free_sample && last_info == free_info) return; /* remove the records from preset table */ for (i = 0; i < AWE_MAX_PRESETS; i++) { prevp = &preset_table[i]; for (maxc = AWE_MAX_INFOS, p = preset_table[i]; p && maxc; p = nextp, maxc--) { nextp = p->next_bank; p = awe_get_removed_li
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -