/* * define the following if you want to use this pcm with non-interleaved mode
*/ /* #define USE_NONINTERLEAVE */
/* NOTE: for using the non-interleaved mode with alsa-lib, you have to set * mmap_emulation flag to 1 in your .asoundrc, such like * * pcm.emu8k { * type plug * slave.pcm { * type hw * card 0 * device 1 * mmap_emulation 1 * } * } * * besides, for the time being, the non-interleaved mode doesn't work well on * alsa-lib...
*/
unsignedint allocated_bytes; struct snd_util_memblk *block; unsignedint offset; unsignedint buf_size; unsignedint period_size; unsignedint loop_start[2]; unsignedint pitch; int panning[2]; int last_ptr; int period_pos; int voices; unsignedint dram_opened: 1; unsignedint running: 1; unsignedint timer_running: 1; struct timer_list timer;
spinlock_t timer_lock;
};
#define LOOP_BLANK_SIZE 8
/* * open up channels for the simultaneous data transfer and playback
*/ staticint
emu8k_open_dram_for_pcm(struct snd_emu8000 *emu, int channels)
{ int i;
/* reserve up to 2 voices for playback */
snd_emux_lock_voice(emu->emu, 0); if (channels > 1)
snd_emux_lock_voice(emu->emu, 1);
/* reserve 28 voices for loading */ for (i = channels + 1; i < EMU8000_DRAM_VOICES; i++) { unsignedint mode = EMU8000_RAM_WRITE;
snd_emux_lock_voice(emu->emu, i); #ifndef USE_NONINTERLEAVE if (channels > 1 && (i & 1) != 0)
mode |= EMU8000_RAM_RIGHT; #endif
snd_emu8000_dma_chan(emu, i, mode);
}
/*
*/ staticvoid
snd_emu8000_write_wait(struct snd_emu8000 *emu, int can_schedule)
{ while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { if (can_schedule) {
schedule_timeout_interruptible(1); if (signal_pending(current)) break;
}
}
}
/* * close all channels
*/ staticvoid
emu8k_close_dram(struct snd_emu8000 *emu)
{ int i;
for (i = 0; i < 2; i++)
snd_emux_unlock_voice(emu->emu, i); for (; i < EMU8000_DRAM_VOICES; i++) {
snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE);
snd_emux_unlock_voice(emu->emu, i);
}
}
/* * convert Hz to AWE32 rate offset (see emux/soundfont.c)
*/
/* * get the current position at the given channel from CCCA register
*/ staticinlineint emu8k_get_curpos(struct snd_emu8k_pcm *rec, int ch)
{ int val = EMU8000_CCCA_READ(rec->emu, ch) & 0xfffffff;
val -= rec->loop_start[ch] - 1; return val;
}
/* * timer interrupt handler * check the current position and update the period if necessary.
*/ staticvoid emu8k_pcm_timer_func(struct timer_list *t)
{ struct snd_emu8k_pcm *rec = timer_container_of(rec, t, timer); int ptr, delta;
/* use timer to update periods.. (specified in msec) */
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
DIV_ROUND_UP(1000000, HZ), UINT_MAX);
/* * this macro should be inserted in the copy/silence loops * to reduce the latency. without this, the system will hang up * during the whole loop.
*/ #define CHECK_SCHEDULER() \ do { \
cond_resched();\ if (signal_pending(current))\ return -EAGAIN;\
} while (0)
#define GET_VAL(sval, iter) \ do { \ if (!iter) \
sval = 0; \ elseif (copy_from_iter(&sval, 2, iter) != 2) \ return -EFAULT; \
} while (0)
/* * copy the interleaved data can be done easily by using * DMA "left" and "right" channels on emu8k engine.
*/ staticint emu8k_pcm_copy(struct snd_pcm_substream *subs, int voice, unsignedlong pos, struct iov_iter *src, unsignedlong count)
{ struct snd_emu8k_pcm *rec = subs->runtime->private_data;
if (rec->block) { /* reallocation - release the old block */
snd_util_mem_free(rec->emu->memhdr, rec->block);
rec->block = NULL;
}
rec->allocated_bytes = params_buffer_bytes(hw_params) + LOOP_BLANK_SIZE * 4;
rec->block = snd_util_mem_alloc(rec->emu->memhdr, rec->allocated_bytes); if (! rec->block) return -ENOMEM;
rec->offset = EMU8000_DRAM_OFFSET + (rec->block->offset >> 1); /* in word */ /* at least dma_bytes must be set for non-interleaved mode */
subs->dma_buffer.bytes = params_buffer_bytes(hw_params);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.