forked from len0rd/rockbox
Initial commit for the Sony NWZ linux port
SUPPORTED SERIES: - NWZ-E450 - NWZ-E460 - NWZ-E470 - NWZ-E580 - NWZ-A10 NOTES: - bootloader makefile convert an extra font to be installed alongside the bootloader since sysfont is way too small - the toolsicon bitmap comes from the Oxygen iconset - touchscreen driver is untested TODO: - implement audio routing driver (pcm is handled by pcm-alsa) - fix playback: it crashes on illegal instruction in DEBUG builds - find out why the browser starts at / instead of /contents - implement radio support - implement return to OF for usb handling - calibrate battery curve (NB: of can report a battery level on a 0-5 scale but probabl don't want to use that ?) - implement simulator build (we need a nice image of the player) - figure out if we can detect jack removal POTENTIAL TODOS: - try to build a usb serial gadget and gdbserver Change-Id: Ic77d71e0651355d47cc4e423a40fb64a60c69a80
This commit is contained in:
parent
142f80f07d
commit
1d121e8c08
89 changed files with 4439 additions and 2913 deletions
|
|
@ -50,12 +50,14 @@
|
|||
#include "system.h"
|
||||
#include "debug.h"
|
||||
#include "kernel.h"
|
||||
#include "panic.h"
|
||||
|
||||
#include "pcm.h"
|
||||
#include "pcm-internal.h"
|
||||
#include "pcm_mixer.h"
|
||||
#include "pcm_sampr.h"
|
||||
#include "audiohw.h"
|
||||
#include "pcm-alsa.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -66,14 +68,21 @@
|
|||
* with multple applications running */
|
||||
static char device[] = "plughw:0,0"; /* playback device */
|
||||
static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */
|
||||
#ifdef SONY_NWZ_LINUX
|
||||
/* Sony NWZ must use 32-bit per sample */
|
||||
static const snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; /* sample format */
|
||||
typedef long sample_t;
|
||||
#else
|
||||
static const snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */
|
||||
typedef short sample_t;
|
||||
#endif
|
||||
static const int channels = 2; /* count of channels */
|
||||
static unsigned int rate = 44100; /* stream rate */
|
||||
|
||||
static snd_pcm_t *handle;
|
||||
static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */
|
||||
static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */
|
||||
static short *frames;
|
||||
static sample_t *frames;
|
||||
|
||||
static const void *pcm_data = 0;
|
||||
static size_t pcm_size = 0;
|
||||
|
|
@ -153,7 +162,7 @@ static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate)
|
|||
goto error;
|
||||
}
|
||||
if (!frames)
|
||||
frames = malloc(period_size * channels * sizeof(short));
|
||||
frames = malloc(period_size * channels * sizeof(sample_t));
|
||||
|
||||
/* write the parameters to device */
|
||||
err = snd_pcm_hw_params(handle, params);
|
||||
|
|
@ -212,6 +221,40 @@ error:
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef SONY_NWZ_LINUX
|
||||
/* Digital volume explanation:
|
||||
* with very good approximation (<0.1dB) the convertion from dB to multiplicative
|
||||
* factor, for dB>=0, is 2^(dB/3). We can then notice that if we write dB=3*k+r
|
||||
* then this is 2^k*2^(r/3) so we only need to look at r=0,1,2. For r=0 this is
|
||||
* 1, for r=1 we have 2^(1/3)~=1.25 so we approximate by 1+1/4, and 2^(2/3)~=1.5
|
||||
* so we approximate by 1+1/2. To go from negative to nonnegative we notice that
|
||||
* 48 dB => 63095 factor ~= 2^16 so we virtually pre-multiply everything by 2^(-16)
|
||||
* and add 48dB to the input volume. We cannot go lower -43dB because several
|
||||
* values between -48dB and -43dB would require a fractional multiplier, which is
|
||||
* stupid to implement for such very low volume. */
|
||||
static int dig_vol_mult = 2 ^ 16; /* multiplicative factor to apply to each sample */
|
||||
|
||||
void pcm_alsa_set_digital_volume(int vol_db)
|
||||
{
|
||||
if(vol_db > 0 || vol_db < -43)
|
||||
panicf("invalid pcm alsa volume");
|
||||
if(format != SND_PCM_FORMAT_S32_LE)
|
||||
panicf("this function assumes 32-bit sample size");
|
||||
vol_db += 48; /* -42dB .. 0dB => 5dB .. 48dB */
|
||||
/* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0
|
||||
* otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */
|
||||
int vol_shift = vol_db / 3;
|
||||
int r = vol_db % 3;
|
||||
if(r == 0)
|
||||
dig_vol_mult = 1 << vol_shift;
|
||||
else if(r == 1)
|
||||
dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 2);
|
||||
else
|
||||
dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 1);
|
||||
printf("%d dB -> factor = %d\n", vol_db - 48, dig_vol_mult);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */
|
||||
static bool fill_frames(void)
|
||||
{
|
||||
|
|
@ -229,12 +272,28 @@ static bool fill_frames(void)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
copy_n = MIN((ssize_t)pcm_size, frames_left*4);
|
||||
memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n);
|
||||
|
||||
pcm_data += copy_n;
|
||||
pcm_size -= copy_n;
|
||||
frames_left -= copy_n/4;
|
||||
if (pcm_size % 4)
|
||||
panicf("Wrong pcm_size");
|
||||
/* the compiler will optimize this test away */
|
||||
copy_n = MIN((ssize_t)pcm_size/4, frames_left);
|
||||
if (format == SND_PCM_FORMAT_S32_LE)
|
||||
{
|
||||
/* We have to convert 16-bit to 32-bit, the need to multiply the
|
||||
* sample by some value so the sound is not too low */
|
||||
const short *pcm_ptr = pcm_data;
|
||||
sample_t *sample_ptr = &frames[2*(period_size-frames_left)];
|
||||
for (int i = 0; i < copy_n*2; i++)
|
||||
*sample_ptr++ = *pcm_ptr++ * dig_vol_mult;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rockbox and PCM have same format: memcopy */
|
||||
memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n);
|
||||
}
|
||||
pcm_data += copy_n*4;
|
||||
pcm_size -= copy_n*4;
|
||||
frames_left -= copy_n;
|
||||
|
||||
if (new_buffer)
|
||||
{
|
||||
|
|
@ -285,7 +344,7 @@ static int async_rw(snd_pcm_t *handle)
|
|||
{
|
||||
int err;
|
||||
snd_pcm_sframes_t sample_size;
|
||||
short *samples;
|
||||
sample_t *samples;
|
||||
|
||||
#ifdef USE_ASYNC_CALLBACK
|
||||
/* assign alternative stack for the signal handlers */
|
||||
|
|
@ -323,7 +382,7 @@ static int async_rw(snd_pcm_t *handle)
|
|||
|
||||
/* fill buffer with silence to initiate playback without noisy click */
|
||||
sample_size = buffer_size;
|
||||
samples = malloc(sample_size * channels * sizeof(short));
|
||||
samples = malloc(sample_size * channels * sizeof(sample_t));
|
||||
|
||||
snd_pcm_format_set_silence(format, samples, sample_size);
|
||||
err = snd_pcm_writei(handle, samples, sample_size);
|
||||
|
|
@ -367,23 +426,19 @@ void pcm_play_dma_init(void)
|
|||
|
||||
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
|
||||
{
|
||||
printf("%s(): Cannot open device %s: %s\n", __func__, device, snd_strerror(err));
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
panicf("%s(): Cannot open device %s: %s\n", __func__, device, snd_strerror(err));
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_nonblock(handle, 1)))
|
||||
printf("Could not set non-block mode: %s\n", snd_strerror(err));
|
||||
panicf("Could not set non-block mode: %s\n", snd_strerror(err));
|
||||
|
||||
if ((err = set_hwparams(handle, rate)) < 0)
|
||||
{
|
||||
printf("Setting of hwparams failed: %s\n", snd_strerror(err));
|
||||
exit(EXIT_FAILURE);
|
||||
panicf("Setting of hwparams failed: %s\n", snd_strerror(err));
|
||||
}
|
||||
if ((err = set_swparams(handle)) < 0)
|
||||
{
|
||||
printf("Setting of swparams failed: %s\n", snd_strerror(err));
|
||||
exit(EXIT_FAILURE);
|
||||
panicf("Setting of swparams failed: %s\n", snd_strerror(err));
|
||||
}
|
||||
|
||||
pcm_dma_apply_settings();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue