📄 wavefront_synth.c
字号:
return outval;};static unsigned char *munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size){ unsigned int i; unsigned int last = dst_size / 2; for (i = 0; i < last; i++) { *dst++ = src[i] & 0x7f; *dst++ = src[i] >> 7; } return dst;}static unsigned char *demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes){ int i; unsigned char *end = src + src_bytes; end = src + src_bytes; /* NOTE: src and dst *CAN* point to the same address */ for (i = 0; src != end; i++) { dst[i] = *src++; dst[i] |= (*src++)<<7; } return dst;}/***********************************************************************WaveFront: sample, patch and program management.***********************************************************************/static intwavefront_delete_sample (snd_wavefront_t *dev, int sample_num){ unsigned char wbuf[2]; int x; wbuf[0] = sample_num & 0x7f; wbuf[1] = sample_num >> 7; if ((x = snd_wavefront_cmd (dev, WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { dev->sample_status[sample_num] = WF_ST_EMPTY; } return x;}static intwavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom){ int i; unsigned char rbuf[32], wbuf[32]; unsigned int sc_real, sc_alias, sc_multi; /* check sample status */ if (snd_wavefront_cmd (dev, WFC_GET_NSAMPLES, rbuf, wbuf)) { snd_printk ("cannot request sample count.\n"); return -1; } sc_real = sc_alias = sc_multi = dev->samples_used = 0; for (i = 0; i < WF_MAX_SAMPLE; i++) { wbuf[0] = i & 0x7f; wbuf[1] = i >> 7; if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { snd_printk("cannot identify sample " "type of slot %d\n", i); dev->sample_status[i] = WF_ST_EMPTY; continue; } dev->sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); if (assume_rom) { dev->sample_status[i] |= WF_SLOT_ROM; } switch (rbuf[0] & WF_ST_MASK) { case WF_ST_SAMPLE: sc_real++; break; case WF_ST_MULTISAMPLE: sc_multi++; break; case WF_ST_ALIAS: sc_alias++; break; case WF_ST_EMPTY: break; default: snd_printk ("unknown sample type for " "slot %d (0x%x)\n", i, rbuf[0]); } if (rbuf[0] != WF_ST_EMPTY) { dev->samples_used++; } } snd_printk ("%d samples used (%d real, %d aliases, %d multi), " "%d empty\n", dev->samples_used, sc_real, sc_alias, sc_multi, WF_MAX_SAMPLE - dev->samples_used); return (0);}static intwavefront_get_patch_status (snd_wavefront_t *dev){ unsigned char patchbuf[WF_PATCH_BYTES]; unsigned char patchnum[2]; wavefront_patch *p; int i, x, cnt, cnt2; for (i = 0; i < WF_MAX_PATCH; i++) { patchnum[0] = i & 0x7f; patchnum[1] = i >> 7; if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PATCH, patchbuf, patchnum)) == 0) { dev->patch_status[i] |= WF_SLOT_FILLED; p = (wavefront_patch *) patchbuf; dev->sample_status [p->sample_number|(p->sample_msb<<7)] |= WF_SLOT_USED; } else if (x == 3) { /* Bad patch number */ dev->patch_status[i] = 0; } else { snd_printk ("upload patch " "error 0x%x\n", x); dev->patch_status[i] = 0; return 1; } } /* program status has already filled in slot_used bits */ for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { if (dev->patch_status[i] & WF_SLOT_FILLED) { cnt++; } if (dev->patch_status[i] & WF_SLOT_USED) { cnt2++; } } snd_printk ("%d patch slots filled, %d in use\n", cnt, cnt2); return (0);}static intwavefront_get_program_status (snd_wavefront_t *dev){ unsigned char progbuf[WF_PROGRAM_BYTES]; wavefront_program prog; unsigned char prognum; int i, x, l, cnt; for (i = 0; i < WF_MAX_PROGRAM; i++) { prognum = i; if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PROGRAM, progbuf, &prognum)) == 0) { dev->prog_status[i] |= WF_SLOT_USED; demunge_buf (progbuf, (unsigned char *) &prog, WF_PROGRAM_BYTES); for (l = 0; l < WF_NUM_LAYERS; l++) { if (prog.layer[l].mute) { dev->patch_status [prog.layer[l].patch_number] |= WF_SLOT_USED; } } } else if (x == 1) { /* Bad program number */ dev->prog_status[i] = 0; } else { snd_printk ("upload program " "error 0x%x\n", x); dev->prog_status[i] = 0; } } for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { if (dev->prog_status[i]) { cnt++; } } snd_printk ("%d programs slots in use\n", cnt); return (0);}static intwavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header){ unsigned char buf[WF_PATCH_BYTES+2]; unsigned char *bptr; DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", header->number); dev->patch_status[header->number] |= WF_SLOT_FILLED; bptr = buf; bptr = munge_int32 (header->number, buf, 2); munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) { snd_printk ("download patch failed\n"); return -(EIO); } return (0);}static intwavefront_send_program (snd_wavefront_t *dev, wavefront_patch_info *header){ unsigned char buf[WF_PROGRAM_BYTES+1]; int i; DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", header->number); dev->prog_status[header->number] = WF_SLOT_USED; /* XXX need to zero existing SLOT_USED bit for program_status[i] where `i' is the program that's being (potentially) overwritten. */ for (i = 0; i < WF_NUM_LAYERS; i++) { if (header->hdr.pr.layer[i].mute) { dev->patch_status[header->hdr.pr.layer[i].patch_number] |= WF_SLOT_USED; /* XXX need to mark SLOT_USED for sample used by patch_number, but this means we have to load it. Ick. */ } } buf[0] = header->number; munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) { snd_printk ("download patch failed\n"); return -(EIO); } return (0);}static intwavefront_freemem (snd_wavefront_t *dev){ char rbuf[8]; if (snd_wavefront_cmd (dev, WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { snd_printk ("can't get memory stats.\n"); return -1; } else { return demunge_int32 (rbuf, 4); }}static intwavefront_send_sample (snd_wavefront_t *dev, wavefront_patch_info *header, u16 __user *dataptr, int data_is_unsigned){ /* samples are downloaded via a 16-bit wide i/o port (you could think of it as 2 adjacent 8-bit wide ports but its less efficient that way). therefore, all the blocksizes and so forth listed in the documentation, and used conventionally to refer to sample sizes, which are given in 8-bit units (bytes), need to be divided by 2. */ u16 sample_short; u32 length; u16 __user *data_end = NULL; unsigned int i; const unsigned int max_blksize = 4096/2; unsigned int written; unsigned int blocksize; int dma_ack; int blocknum; unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; unsigned char *shptr; int skip = 0; int initial_skip = 0; DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " "type %d, %d bytes from 0x%lx\n", header->size ? "" : "header ", header->number, header->subkey, header->size, (unsigned long) header->dataptr); if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { int x; if ((x = wavefront_find_free_sample (dev)) < 0) { return -ENOMEM; } snd_printk ("unspecified sample => %d\n", x); header->number = x; } if (header->size) { /* XXX it's a debatable point whether or not RDONLY semantics on the ROM samples should cover just the sample data or the sample header. For now, it only covers the sample data, so anyone is free at all times to rewrite sample headers. My reason for this is that we have the sample headers available in the WFB file for General MIDI, and so these can always be reset if needed. The sample data, however, cannot be recovered without a complete reset and firmware reload of the ICS2115, which is a very expensive operation. So, doing things this way allows us to honor the notion of "RESETSAMPLES" reasonably cheaply. Note however, that this is done purely at user level: there is no WFB parser in this driver, and so a complete reset (back to General MIDI, or theoretically some other configuration) is the responsibility of the user level library. To try to do this in the kernel would be a little crazy: we'd need 158K of kernel space just to hold a copy of the patch/program/sample header data. */ if (dev->rom_samples_rdonly) { if (dev->sample_status[header->number] & WF_SLOT_ROM) { snd_printk ("sample slot %d " "write protected\n", header->number); return -EACCES; } } wavefront_delete_sample (dev, header->number); } if (header->size) { dev->freemem = wavefront_freemem (dev); if (dev->freemem < (int)header->size) { snd_printk ("insufficient memory to " "load %d byte sample.\n", header->size); return -ENOMEM; } } skip = WF_GET_CHANNEL(&header->hdr.s); if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { snd_printk ("channel selection only " "possible on 16-bit samples"); return -(EINVAL); } switch (skip) { case 0: initial_skip = 0; skip = 1; break; case 1: initial_skip = 0; skip = 2; break; case 2: initial_skip = 1; skip = 2; break; case 3: initial_skip = 2; skip = 3; break; case 4: initial_skip = 3; skip = 4; break; case 5: initial_skip = 4; skip = 5; break; case 6: initial_skip = 5; skip = 6; break; } DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " "initial skip = %d, skip = %d\n", WF_GET_CHANNEL (&header->hdr.s), initial_skip, skip); /* Be safe, and zero the "Unused" bits ... */ WF_SET_CHANNEL(&header->hdr.s, 0); /* adjust size for 16 bit samples by dividing by two. We always send 16 bits per write, even for 8 bit samples, so the length is always half the size of the sample data in bytes. */ length = header->size / 2; /* the data we're sent has not been munged, and in fact, the header we have to send isn't just a munged copy either. so, build the sample header right here. */ shptr = &sample_hdr[0]; shptr = munge_int32 (header->number, shptr, 2); if (header->size) { shptr = munge_int32 (length, shptr, 4); } /* Yes, a 4 byte result doesn't contain all of the offset bits, but the offset only uses 24 bits. */ shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleStartOffset), shptr, 4); shptr = munge_int32 (*((u32 *) &header->hdr.s.loopStartOffset), shptr, 4); shptr = munge_int32 (*((u32 *) &header->hdr.s.loopEndOffset), shptr, 4); shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleEndOffset), shptr, 4); /* This one is truly weird. What kind of weirdo decided that in a system dominated by 16 and 32 bit integers, they would use a just 12 bits ? */ shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); /* Why is this nybblified, when the MSB is *always* zero ? Anyway, we can't take address of bitfield, so make a good-faith guess at where it starts. */ shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), shptr, 2); if (snd_wavefront_cmd (dev, header->size ? WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, NULL, sample_hdr)) { snd_printk ("sample %sdownload refused.\n", header->size ? "" : "header "); return -(EIO); } if (header->size == 0) { goto sent; /* Sorry. Just had to have one somewhere */ } data_end = dataptr + length; /* Do any initial skip over an unused channel's data */ dataptr += initial_skip; for (written = 0, blocknum = 0; written < length; written += max_blksize, blocknum++) { if ((length - written) > max_blksize) { blocksize = max_blksize; } else { /* round to nearest 16-byte value */ blocksize = ((length-written+7)&~0x7); } if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) { snd_printk ("download block " "request refused.\n"); return -(EIO); } for (i = 0; i < blocksize; i++) { if (dataptr < data_end) { __get_user (sample_short, dataptr); dataptr += skip; if (data_is_unsigned) { /* GUS ? */ if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { /* 8 bit sample resolution, sign extend both bytes. */ ((unsigned char*) &sample_short)[0] += 0x7f; ((unsigned char*) &sample_short)[1] += 0x7f; } else { /* 16 bit sample resolution, sign extend the MSB. */ sample_short += 0x7fff; } } } else { /* In padding section of final block:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -