Update of /cvsroot/alsa/alsa-lib/src/pcm In directory sc8-pr-cvs1:/tmp/cvs-serv15951/src/pcm
Modified Files: pcm_dmix.c pcm_dmix_i386.h Log Message: Added 32-bit sample support to dmix plugin Index: pcm_dmix.c =================================================================== RCS file: /cvsroot/alsa/alsa-lib/src/pcm/pcm_dmix.c,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- pcm_dmix.c 1 Mar 2003 20:18:50 -0000 1.26 +++ pcm_dmix.c 18 Mar 2003 14:15:20 -0000 1.27 @@ -73,19 +73,24 @@ volatile signed int *sum, unsigned int dst_step, unsigned int src_step, unsigned int sum_step); +typedef void (mix_areas2_t)(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, unsigned int dst_step, + unsigned int src_step, unsigned int sum_step); + /* * */ struct slave_params { snd_pcm_format_t format; - unsigned int rate; - unsigned int channels; - unsigned int period_time; - unsigned int buffer_time; - snd_pcm_uframes_t period_size; - snd_pcm_uframes_t buffer_size; - unsigned int periods; + int rate; + int channels; + int period_time; + int buffer_time; + snd_pcm_sframes_t period_size; + snd_pcm_sframes_t buffer_size; + int periods; }; typedef struct { @@ -128,6 +133,7 @@ snd_timer_t *timer; /* timer used as poll_fd */ int interleaved; /* we have interleaved buffer */ mix_areas1_t *mix_areas1; + mix_areas2_t *mix_areas2; } snd_pcm_dmix_t; /* @@ -585,18 +591,22 @@ #define MIX_AREAS1 mix_areas1 #define MIX_AREAS1_MMX mix_areas1_mmx +#define MIX_AREAS2 mix_areas2 #define LOCK_PREFIX "" #include "pcm_dmix_i386.h" #undef MIX_AREAS1 #undef MIX_AREAS1_MMX +#undef MIX_AREAS2 #undef LOCK_PREFIX #define MIX_AREAS1 mix_areas1_smp #define MIX_AREAS1_MMX mix_areas1_smp_mmx +#define MIX_AREAS2 mix_areas2_smp #define LOCK_PREFIX "lock ; " #include "pcm_dmix_i386.h" #undef MIX_AREAS1 #undef MIX_AREAS1_MMX +#undef MIX_AREAS2 #undef LOCK_PREFIX static void mix_select_callbacks(snd_pcm_dmix_t *dmix) @@ -627,6 +637,7 @@ } else { dmix->mix_areas1 = smp > 1 ? mix_areas1_smp : mix_areas1; } + dmix->mix_areas2 = smp > 1 ? mix_areas2_smp : mix_areas2; } #endif @@ -661,9 +672,40 @@ } } +#warning Please, recode mix_areas2() routine to your architecture... +static void mix_areas2(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, unsigned int dst_step, + unsigned int src_step, unsigned int sum_step) +{ + register signed int sample, old_sample; + + while (size-- > 0) { + sample = *src >> 8; + old_sample = *sum; + if (*dst == 0) + sample -= old_sample; + *sum += sample; + do { + old_sample = *sum; + if (old_sample > 0x7fffff) + sample = 0x7fffff; + else if (old_sample < -0x800000) + sample = -0x800000; + else + sample = old_sample; + *dst = sample; + } while (*sum != old_sample); + ((char *)src) += src_step; + ((char *)dst) += dst_step; + ((char *)sum) += sum_step; + } +} + static void mix_select_callbacks(snd_pcm_dmix_t *dmix) { dmix->mix_areas1 = mix_areas1; + dmix->mix_areas2 = mix_areas2; } #endif @@ -674,34 +716,61 @@ snd_pcm_uframes_t dst_ofs, snd_pcm_uframes_t size) { - signed short *src; - volatile signed short *dst; volatile signed int *sum; unsigned int src_step, dst_step; unsigned int chn, channels; channels = dmix->shmptr->s.channels; - if (dmix->interleaved) { - /* - * process all areas in one loop - * it optimizes the memory accesses for this case - */ - dmix->mix_areas1(size * channels, - ((signed short *)dst_areas[0].addr) + (dst_ofs * channels), - ((signed short *)src_areas[0].addr) + (src_ofs * channels), - dmix->sum_buffer + (dst_ofs * channels), - sizeof(signed short), - sizeof(signed short), - sizeof(signed int)); - return; - } - for (chn = 0; chn < channels; chn++) { - src_step = src_areas[chn].step / 8; - dst_step = dst_areas[chn].step / 8; - src = (signed short *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step)); - dst = (signed short *)(((char *)dst_areas[chn].addr + dst_areas[chn].first / 8) + (dst_ofs * dst_step)); - sum = dmix->sum_buffer + channels * dst_ofs + chn; - dmix->mix_areas1(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int)); + if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16) { + signed short *src; + volatile signed short *dst; + if (dmix->interleaved) { + /* + * process all areas in one loop + * it optimizes the memory accesses for this case + */ + dmix->mix_areas1(size * channels, + ((signed short *)dst_areas[0].addr) + (dst_ofs * channels), + ((signed short *)src_areas[0].addr) + (src_ofs * channels), + dmix->sum_buffer + (dst_ofs * channels), + sizeof(signed short), + sizeof(signed short), + sizeof(signed int)); + return; + } + for (chn = 0; chn < channels; chn++) { + src_step = src_areas[chn].step / 8; + dst_step = dst_areas[chn].step / 8; + src = (signed short *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step)); + dst = (signed short *)(((char *)dst_areas[chn].addr + dst_areas[chn].first / 8) + (dst_ofs * dst_step)); + sum = dmix->sum_buffer + channels * dst_ofs + chn; + dmix->mix_areas1(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int)); + } + } else { + signed int *src; + volatile signed int *dst; + if (dmix->interleaved) { + /* + * process all areas in one loop + * it optimizes the memory accesses for this case + */ + dmix->mix_areas2(size * channels, + ((signed int *)dst_areas[0].addr) + (dst_ofs * channels), + ((signed int *)src_areas[0].addr) + (src_ofs * channels), + dmix->sum_buffer + (dst_ofs * channels), + sizeof(signed int), + sizeof(signed int), + sizeof(signed int)); + return; + } + for (chn = 0; chn < channels; chn++) { + src_step = src_areas[chn].step / 8; + dst_step = dst_areas[chn].step / 8; + src = (signed int *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step)); + dst = (signed int *)(((char *)dst_areas[chn].addr + dst_areas[chn].first / 8) + (dst_ofs * dst_step)); + sum = dmix->sum_buffer + channels * dst_ofs + chn; + dmix->mix_areas2(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int)); + } } } @@ -845,7 +914,7 @@ return 0; i = hw_param_interval(params, var); if (snd_interval_empty(i)) { - SNDERR("dmix interval %i empty?\n", (int)var); + SNDERR("dmix interval %i empty?", (int)var); return -EINVAL; } if (snd_interval_refine(i, hw_param_interval(src, var))) @@ -876,7 +945,7 @@ if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) { if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) { - SNDERR("dmix access mask empty?\n"); + SNDERR("dmix access mask empty?"); return -EINVAL; } if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access)) @@ -884,7 +953,7 @@ } if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) { if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) { - SNDERR("dmix format mask empty?\n"); + SNDERR("dmix format mask empty?"); return -EINVAL; } if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT), @@ -1268,10 +1337,16 @@ int ret, buffer_is_not_initialized; snd_pcm_uframes_t boundary; struct pollfd fd; + int loops = 10; hw_params = &dmix->shmptr->hw_params; sw_params = &dmix->shmptr->sw_params; + __again: + if (loops-- <= 0) { + SNDERR("unable to find a valid configuration for slave"); + return -EINVAL; + } ret = snd_pcm_hw_params_any(spcm, hw_params); if (ret < 0) { SNDERR("snd_pcm_hw_params_any failed"); @@ -1287,13 +1362,43 @@ } ret = snd_pcm_hw_params_set_format(spcm, hw_params, params->format); if (ret < 0) { - SNDERR("requested format is not available"); - return ret; + snd_pcm_format_t format; + switch (params->format) { + case SND_PCM_FORMAT_S32: format = SND_PCM_FORMAT_S16; break; + case SND_PCM_FORMAT_S16: format = SND_PCM_FORMAT_S32; break; + default: + SNDERR("invalid format"); + return -EINVAL; + } + ret = snd_pcm_hw_params_set_format(spcm, hw_params, format); + if (ret < 0) { + SNDERR("requested or auto-format is not available"); + return ret; + } + params->format = format; } ret = snd_pcm_hw_params_set_channels(spcm, hw_params, params->channels); if (ret < 0) { - SNDERR("requested count of channels is not available"); - return ret; + unsigned int min, max; + ret = INTERNAL(snd_pcm_hw_params_get_channels_min)(hw_params, &min); + if (ret < 0) { + SNDERR("cannot obtain minimal count of channels"); + return ret; + } + ret = INTERNAL(snd_pcm_hw_params_get_channels_min)(hw_params, &max); + if (ret < 0) { + SNDERR("cannot obtain maximal count of channels"); + return ret; + } + if (min == max) { + ret = snd_pcm_hw_params_set_channels(spcm, hw_params, min); + if (ret >= 0) + params->channels = min; + } + if (ret < 0) { + SNDERR("requested count of channels is not available"); + return ret; + } } ret = INTERNAL(snd_pcm_hw_params_set_rate_near)(spcm, hw_params, ¶ms->rate, 0); if (ret < 0) { @@ -1333,11 +1438,24 @@ } if (buffer_is_not_initialized && params->periods > 0) { + int periods = params->periods; ret = INTERNAL(snd_pcm_hw_params_set_periods_near)(spcm, hw_params, ¶ms->periods, 0); if (ret < 0) { SNDERR("unable to set requested periods"); return ret; } + if (params->periods == 1) { + params->periods = periods; + if (params->period_time > 0) { + params->period_time /= 2; + goto __again; + } else if (params->period_size > 0) { + params->period_size /= 2; + goto __again; + } + SNDERR("unable to use stream with periods == 1"); + return ret; + } } ret = snd_pcm_hw_params(spcm, hw_params); @@ -1354,22 +1472,22 @@ ret = snd_pcm_sw_params_get_boundary(sw_params, &boundary); if (ret < 0) { - SNDERR("unable to get boundary\n"); + SNDERR("unable to get boundary"); return ret; } ret = snd_pcm_sw_params_set_stop_threshold(spcm, sw_params, boundary); if (ret < 0) { - SNDERR("unable to set stop threshold\n"); + SNDERR("unable to set stop threshold"); return ret; } ret = snd_pcm_sw_params_set_silence_threshold(spcm, sw_params, 0); if (ret < 0) { - SNDERR("unable to set silence threshold\n"); + SNDERR("unable to set silence threshold"); return ret; } ret = snd_pcm_sw_params_set_silence_size(spcm, sw_params, boundary); if (ret < 0) { - SNDERR("unable to set silence threshold (please upgrade to 0.9.0rc8+ driver)\n"); + SNDERR("unable to set silence threshold (please upgrade to 0.9.0rc8+ driver)"); return ret; } @@ -1381,12 +1499,12 @@ ret = snd_pcm_start(spcm); if (ret < 0) { - SNDERR("unable to start PCM stream\n"); + SNDERR("unable to start PCM stream"); return ret; } if (snd_pcm_poll_descriptors_count(spcm) != 1) { - SNDERR("unable to use hardware pcm with fd more than one!!!\n"); + SNDERR("unable to use hardware pcm with fd more than one!!!"); return ret; } snd_pcm_poll_descriptors(spcm, &fd, 1); @@ -1421,7 +1539,7 @@ snd_timer_params_alloca(¶ms); ret = snd_pcm_info(dmix->spcm, info); if (ret < 0) { - SNDERR("unable to info for slave pcm\n"); + SNDERR("unable to info for slave pcm"); return ret; } sprintf(name, "hw:CLASS=%i,SCLASS=0,CARD=%i,DEV=%i,SUBDEV=%i", @@ -1431,18 +1549,18 @@ snd_pcm_info_get_subdevice(info) * 2); /* it's a bit trick to distict playback and capture */ ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK); if (ret < 0) { - SNDERR("unable to open timer '%s'\n", name); + SNDERR("unable to open timer '%s'", name); return ret; } snd_timer_params_set_auto_start(params, 1); snd_timer_params_set_ticks(params, 1); ret = snd_timer_params(dmix->timer, params); if (ret < 0) { - SNDERR("unable to set timer parameters\n", name); + SNDERR("unable to set timer parameters", name); return ret; } if (snd_timer_poll_descriptors_count(dmix->timer) != 1) { - SNDERR("unable to use timer with fd more than one!!!\n", name); + SNDERR("unable to use timer with fd more than one!!!", name); return ret; } snd_timer_poll_descriptors(dmix->timer, &fd, 1); @@ -1496,7 +1614,7 @@ ret = semaphore_create_or_connect(dmix); if (ret < 0) { - SNDERR("unable to create IPC semaphore\n"); + SNDERR("unable to create IPC semaphore"); goto _err; } @@ -1508,7 +1626,7 @@ first_instance = ret = shm_create_or_connect(dmix); if (ret < 0) { - SNDERR("unable to create IPC shm instance\n"); + SNDERR("unable to create IPC shm instance"); goto _err; } @@ -1520,7 +1638,7 @@ if (first_instance) { ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); if (ret < 0) { - SNDERR("unable to open slave\n"); + SNDERR("unable to open slave"); goto _err; } @@ -1531,7 +1649,7 @@ ret = snd_pcm_dmix_initialize_slave(dmix, spcm, params); if (ret < 0) { - SNDERR("unable to initialize slave\n"); + SNDERR("unable to initialize slave"); goto _err; } @@ -1539,7 +1657,7 @@ ret = server_create(dmix); if (ret < 0) { - SNDERR("unable to create server\n"); + SNDERR("unable to create server"); goto _err; } @@ -1547,13 +1665,13 @@ } else { ret = client_connect(dmix); if (ret < 0) { - SNDERR("unable to connect client\n"); + SNDERR("unable to connect client"); return ret; } ret = snd_pcm_hw_open_fd(&spcm, "dmix_client", dmix->hw_fd, 0); if (ret < 0) { - SNDERR("unable to open hardware\n"); + SNDERR("unable to open hardware"); goto _err; } @@ -1566,7 +1684,7 @@ spcm->boundary = dmix->shmptr->s.boundary; ret = snd_pcm_mmap(spcm); if (ret < 0) { - SNDERR("unable to mmap channels\n"); + SNDERR("unable to mmap channels"); goto _err; } dmix->spcm = spcm; @@ -1574,13 +1692,13 @@ ret = shm_sum_create_or_connect(dmix); if (ret < 0) { - SNDERR("unabel to initialize sum ring buffer\n"); + SNDERR("unabel to initialize sum ring buffer"); goto _err; } ret = snd_pcm_dmix_initialize_poll_fd(dmix); if (ret < 0) { - SNDERR("unable to initialize poll_fd\n"); + SNDERR("unable to initialize poll_fd"); goto _err; } @@ -1756,7 +1874,13 @@ if (err < 0) return err; - assert(params.format == SND_PCM_FORMAT_S16); /* sorry, limited features */ + /* sorry, limited features */ + if (params.format != SND_PCM_FORMAT_S16 && + params.format != SND_PCM_FORMAT_S32) { + SNDERR("invalid format, specify s16 or s32"); + snd_config_delete(sconf); + return -EINVAL; + } params.period_size = psize; params.buffer_size = bsize; Index: pcm_dmix_i386.h =================================================================== RCS file: /cvsroot/alsa/alsa-lib/src/pcm/pcm_dmix_i386.h,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- pcm_dmix_i386.h 1 Mar 2003 14:23:29 -0000 1.5 +++ pcm_dmix_i386.h 18 Mar 2003 14:15:21 -0000 1.6 @@ -114,8 +114,7 @@ "\t.p2align 4,,15\n" "4:" - "\tmovw $0x7fff, %%ax\n" - "\tmovw %%ax, (%%edi)\n" + "\tmovw $0x7fff, (%%edi)\n" "\tcmpl %%ecx,(%%ebx)\n" "\tjnz 3b\n" "\tadd %4, %%edi\n" @@ -132,8 +131,7 @@ "\t.p2align 4,,15\n" "5:" - "\tmovw $-0x8000, %%ax\n" - "\tmovw %%ax, (%%edi)\n" + "\tmovw $-0x8000, (%%edi)\n" "\tcmpl %%ecx, (%%ebx)\n" "\tjnz 3b\n" "\tadd %4, %%edi\n" @@ -240,3 +238,132 @@ : "esi", "edi", "edx", "ecx", "ebx", "eax" ); } + +/* + * for plain i386, 32-bit version (24-bit resolution) + */ +static void MIX_AREAS2(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, unsigned int dst_step, + unsigned int src_step, unsigned int sum_step) +{ + /* + * ESI - src + * EDI - dst + * EBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovl %1, %%edi\n" + "\tmovl %2, %%esi\n" + "\tmovl %3, %%ebx\n" + + /* + * while (size-- > 0) { + */ + "\tcmp $0, %0\n" + "jz 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (cmpxchg(*dst, 0, 1) == 0) + * sample -= sum_sample; + * xadd(*sum, sample); + */ + "\tmovl $0, %%eax\n" + "\tmovl $1, %%ecx\n" + "\tmovl (%%ebx), %%edx\n" + "\t" LOCK_PREFIX "cmpxchgl %%ecx, (%%edi)\n" + "\tjnz 2f\n" + "\tmovl (%%esi), %%ecx\n" + "\tshr $8, %%ecx\n" + "\tsubl %%edx, %%ecx\n" + "2:" + "\tmovl (%%esi), %%ecx\n" + "\tshr $8, %%ecx\n" + "\t" LOCK_PREFIX "addl %%ecx, (%%ebx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(v); + * *dst = sample; + * } while (v != *sum); + */ + + "3:" + "\tmovl (%%ebx), %%ecx\n" + "\tcmpl $0x7fffff,%%ecx\n" + "\tjg 4f\n" + "\tcmpl $-0x800000,%%ecx\n" + "\tjl 5f\n" + "\tmov %%ecx, %%eax\n" + "\tshl $8, %%eax\n" + "\tmovl %%eax, (%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + "\tjmp 6f\n" + + /* + * sample > 0x7fff00 + */ + + "\t.p2align 4,,15\n" + + "4:" + "\tmovl $0x7fffffff, (%%edi)\n" + "\tcmpl %%ecx,(%%ebx)\n" + "\tjnz 3b\n" + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + "\tjmp 6f\n" + + /* + * sample < -0x800000 + */ + + "\t.p2align 4,,15\n" + + "5:" + "\tmovl $-0x80000000, (%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 3b\n" + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + // "\tjmp 6f\n" + + "6:" + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), "m" (sum), "m" (dst_step), "m" (src_step), "m" (sum_step) + : "esi", "edi", "edx", "ecx", "ebx", "eax" + ); +} + ------------------------------------------------------- This SF.net email is sponsored by: Does your code think in ink? You could win a Tablet PC. Get a free Tablet PC hat just for playing. What are you waiting for? http://ads.sourceforge.net/cgi-bin/redirect.pl?micr5043en _______________________________________________ Alsa-cvslog mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-cvslog