1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <samplerate.h>
#include "codec.h"
#include "playlist.h"
#include "common.h"
extern int sdl_player_freq; // hack!
static SRC_STATE *src;
static SRC_DATA srcdata;
static int codecleft;
static char g_readbuffer[20000]; // hack!
static float g_fbuffer[20000]; // hack!
static float g_srcbuffer[20000]; // hack!
int
streamer_init (void) {
// src = src_new (SRC_LINEAR, 2, NULL);
src = src_new (SRC_SINC_BEST_QUALITY, 2, NULL);
if (!src) {
return -1;
}
codecleft = 0;
return 0;
}
void
streamer_free (void) {
if (src) {
src_delete (src);
src = NULL;
}
}
// returns number of bytes been read
int
streamer_read (char *bytes, int size) {
codec_t *codec = playlist_current.codec;
int bytesread = 0;
if (!codec) {
return 0;
}
// read and do SRC
if (codec->info.samplesPerSecond == sdl_player_freq) {
int i;
if (codec->info.channels == 2) {
codec_lock ();
bytesread = codec->read (bytes, size);
codec_unlock ();
}
else {
codec_lock ();
bytesread = codec->read (g_readbuffer, size/2);
for (i = 0; i < size/4; i++) {
int16_t sample = (int16_t)(((int32_t)(((int16_t*)g_readbuffer)[i])));
((int16_t*)bytes)[i*2+0] = sample;
((int16_t*)bytes)[i*2+1] = sample;
}
bytesread *= 2;
codec_unlock ();
}
}
else {
int nsamples = size/4;
// convert to codec samplerate
// add 5 extra samples for SRC
nsamples = nsamples * codec->info.samplesPerSecond / sdl_player_freq + 5;
// read data at source samplerate (with some room for SRC)
codec_lock ();
int nbytes = (nsamples - codecleft) * 2 * codec->info.channels;
bytesread = codec->read (g_readbuffer, nbytes);
// recalculate nsamples according to how many bytes we've got
nsamples -= (nbytes - bytesread) / (2 * codec->info.channels);
// convert to float, and apply soft volume
int i;
float *fbuffer = g_fbuffer + codecleft*2;
if (codec->info.channels == 2) { // convert mono to stereo
for (i = 0; i < (nsamples - codecleft) * 2; i++) {
fbuffer[i] = ((int16_t *)g_readbuffer)[i]/32767.f;
}
}
else if (codec->info.channels == 1) {
for (i = 0; i < (nsamples - codecleft); i++) {
fbuffer[i*2+0] = ((int16_t *)g_readbuffer)[i];
fbuffer[i*2+1] = fbuffer[i*2+0];
}
}
// convert samplerate
srcdata.data_in = g_fbuffer;
srcdata.data_out = g_srcbuffer;
srcdata.input_frames = nsamples;
srcdata.output_frames = size/4;
srcdata.src_ratio = (double)sdl_player_freq/codec->info.samplesPerSecond;
srcdata.end_of_input = 0;
src_process (src, &srcdata);
// convert back to s16 format
nbytes = size;
int genbytes = srcdata.output_frames_gen * 4;
bytesread = min(size, genbytes);
for (i = 0; i < bytesread/2; i++) {
((int16_t*)bytes)[i] = (int16_t)(g_srcbuffer[i]*32767.f);
}
// calculate how many unused input samples left
codecleft = nsamples - srcdata.input_frames_used;
// copy spare samples for next update
memmove (fbuffer, &fbuffer[srcdata.input_frames_used*2], codecleft * 8);
codec_unlock ();
}
return bytesread;
}
|