Commit cd661690274becf438f26f617e6ec47efdbc3b80
Implemented sinc interpolation.
Christopher Snowhill authored on 1/2/2016, 7:39:06 AMChristopher Snowhill committed on 6/13/2018, 12:10:58 AM
Parent: a598e4485ed3fd07d57f9290824ce35590edec73
Files changed
src/syntrax/syntrax.c | changed |
src/syntrax/syntrax.h | changed |
src/syntrax/resampler.c | added |
src/syntrax/resampler.h | added |
src/syntrax/syntrax.c | ||
---|---|---|
@@ -1,10 +1,14 @@ | ||
1 | 1 | |
2 | 2 | |
3 | + | |
4 | + | |
3 | 5 | |
6 | + | |
4 | 7 | |
5 | 8 | |
6 | 9 | |
10 | + | |
7 | 11 | |
8 | 12 | static void reset(Player *p) |
9 | 13 | { |
10 | 14 | int i, j; |
@@ -96,17 +100,26 @@ | ||
96 | 100 | } |
97 | 101 | |
98 | 102 | void playerDestroy(Player *p) |
99 | 103 | { |
104 | + int i; | |
105 | + | |
100 | 106 | if (p) { |
101 | 107 | if (p->dynamorphTable) free(p->dynamorphTable); |
102 | 108 | if (p->freqTable) free(p->freqTable); |
103 | 109 | if (p->silentBuffer) free(p->silentBuffer); |
104 | 110 | if (p->overlapBuff) free(p->overlapBuff); |
105 | 111 | if (p->delayBufferL) free(p->delayBufferL); |
106 | 112 | if (p->delayBufferR) free(p->delayBufferR); |
107 | 113 | if (p->tuneChannels) free(p->tuneChannels); |
108 | - if (p->voices) free(p->voices); | |
114 | + if (p->voices) { | |
115 | + for (i = 0; i < SE_MAXCHANS; i++) | |
116 | + { | |
117 | + resampler_destroy(p->voices[i].resampler[0]); | |
118 | + resampler_destroy(p->voices[i].resampler[1]); | |
119 | + } | |
120 | + free(p->voices); | |
121 | + } | |
109 | 122 | |
110 | 123 | if (p->instruments) free(p->instruments); |
111 | 124 | |
112 | 125 | free(p); |
@@ -164,8 +177,15 @@ | ||
164 | 177 | if (!p->tuneChannels) goto FAIL; |
165 | 178 | p->voices = malloc(SE_MAXCHANS *sizeof(Voice)); |
166 | 179 | if (!p->voices) goto FAIL; |
167 | 180 | |
181 | + for (i = 0; i < SE_MAXCHANS; i++) | |
182 | + { | |
183 | + p->voices[i].resampler[0] = resampler_create(); | |
184 | + p->voices[i].resampler[1] = resampler_create(); | |
185 | + if (!p->voices[i].resampler[0] || !p->voices[i].resampler[1]) goto FAIL; | |
186 | + } | |
187 | + | |
168 | 188 | reset(p); |
169 | 189 | |
170 | 190 | return p; |
171 | 191 | |
@@ -930,11 +950,11 @@ | ||
930 | 950 | tc->sampleBuffer = p->samples[instrNum - 1]; |
931 | 951 | } else { |
932 | 952 | tc->sampleBuffer = p->samples[ins->shareSmpDataFromInstr - 1]; |
933 | 953 | } |
934 | - tc->sampPos = ins->smpStartPoint << 8; | |
935 | - tc->smpLoopStart = ins->smpLoopPoint << 8; | |
936 | - tc->smpLoopEnd = ins->smpEndPoint << 8; | |
954 | + tc->sampPos = ins->smpStartPoint; | |
955 | + tc->smpLoopStart = ins->smpLoopPoint; | |
956 | + tc->smpLoopEnd = ins->smpEndPoint; | |
937 | 957 | tc->hasLoop = ins->hasLoop; |
938 | 958 | tc->hasBidiLoop = ins->hasBidiLoop; |
939 | 959 | tc->hasLooped = 0; |
940 | 960 | tc->isPlayingBackward = 0; |
@@ -947,8 +967,11 @@ | ||
947 | 967 | memcpy(&tc->synthBuffers[i], &ins->synthBuffers[i], 0x100 *2); |
948 | 968 | } |
949 | 969 | } |
950 | 970 | tc->insNum = instrNum - 1; |
971 | + | |
972 | + resampler_clear(v->resampler[0]); | |
973 | + v->last_delta = 0; | |
951 | 974 | } |
952 | 975 | ins = &p->instruments[tc->insNum]; |
953 | 976 | |
954 | 977 | for (j = 0; j < 4; j++) { |
@@ -1747,9 +1770,9 @@ | ||
1747 | 1770 | } |
1748 | 1771 | else if ( !tc->sampleBuffer ) |
1749 | 1772 | { |
1750 | 1773 | int waveNum = p->instruments[insNum].waveform; |
1751 | - v->wavelength = (p->instruments[insNum].wavelength << 8) - 1; | |
1774 | + v->wavelength = (p->instruments[insNum].wavelength) - 1; | |
1752 | 1775 | v->waveBuff = tc->synthBuffers[waveNum]; |
1753 | 1776 | v->isSample = 0; |
1754 | 1777 | } |
1755 | 1778 | else |
@@ -1769,8 +1792,14 @@ | ||
1769 | 1792 | tc->freq = 10; |
1770 | 1793 | |
1771 | 1794 | v->gain = (tc->volume + 10000) / 39; |
1772 | 1795 | v->delta = (tc->freq << 8) / p->SAMPLEFREQUENCY; |
1796 | + if (v->delta != v->last_delta) | |
1797 | + { | |
1798 | + double fdelta = (double)v->delta * (1.0 / (double)0x100); | |
1799 | + v->last_delta = v->delta; | |
1800 | + resampler_set_rate(v->resampler[0], fdelta); | |
1801 | + } | |
1773 | 1802 | |
1774 | 1803 | if ( v->gain > 0x100 ) |
1775 | 1804 | v->gain = 0x100; |
1776 | 1805 | if ( tc->panning ) |
@@ -1830,65 +1859,80 @@ | ||
1830 | 1859 | { |
1831 | 1860 | v = &p->voices[j]; |
1832 | 1861 | if ( v->isSample == 1 ) |
1833 | 1862 | { |
1834 | - if ( v->sampPos != -1 ) | |
1863 | + if ( v->sampPos != -1 || resampler_get_avail(v->resampler[0]) ) | |
1835 | 1864 | { |
1836 | 1865 | //interpolation |
1837 | - //smp = intp->interpSamp(v); | |
1838 | - smp = v->waveBuff[v->sampPos>>8]; | |
1839 | - | |
1840 | - audioMainR += (smp * v->gainRight) >> 8; | |
1841 | - audioMainL += (smp * v->gainLeft) >> 8; | |
1842 | - audioDelayR += (smp * v->gainDelayRight) >> 8; | |
1843 | - audioDelayL += (smp * v->gainDelayLeft) >> 8; | |
1844 | - if ( v->isPlayingBackward ) | |
1866 | + sample_t s; | |
1867 | + while ( v->sampPos != -1 && resampler_get_min_fill(v->resampler[0]) ) | |
1845 | 1868 | { |
1846 | - v->sampPos -= v->delta; | |
1847 | - if ( v->sampPos <= v->smpLoopStart ) | |
1869 | + s = v->waveBuff[v->sampPos]; | |
1870 | + resampler_write_pair(v->resampler[0], s, s); | |
1871 | + if ( v->isPlayingBackward ) | |
1848 | 1872 | { |
1849 | - v->isPlayingBackward = 0; | |
1850 | - v->sampPos += v->delta; | |
1873 | + v->sampPos--; | |
1874 | + if ( v->sampPos <= v->smpLoopStart ) | |
1875 | + { | |
1876 | + v->isPlayingBackward = 0; | |
1877 | + v->sampPos++; | |
1878 | + } | |
1851 | 1879 | } |
1852 | - } | |
1853 | - else | |
1854 | - { | |
1855 | - v->sampPos += v->delta; | |
1856 | - if ( v->sampPos >= v->smpLoopEnd ) | |
1880 | + else | |
1857 | 1881 | { |
1858 | - if ( v->hasLoop ) | |
1882 | + v->sampPos++; | |
1883 | + if ( v->sampPos >= v->smpLoopEnd ) | |
1859 | 1884 | { |
1860 | - v->hasLooped = 1; | |
1861 | - if ( v->hasBidiLoop ) | |
1885 | + if ( v->hasLoop ) | |
1862 | 1886 | { |
1863 | - v->isPlayingBackward = 1; | |
1864 | - v->sampPos -= v->delta; | |
1887 | + v->hasLooped = 1; | |
1888 | + if ( v->hasBidiLoop ) | |
1889 | + { | |
1890 | + v->isPlayingBackward = 1; | |
1891 | + v->sampPos--; | |
1892 | + } | |
1893 | + else | |
1894 | + { | |
1895 | + v->sampPos += v->smpLoopStart - v->smpLoopEnd; | |
1896 | + } | |
1865 | 1897 | } |
1866 | 1898 | else |
1867 | 1899 | { |
1868 | - v->sampPos += v->smpLoopStart - v->smpLoopEnd; | |
1900 | + v->sampPos = -1; | |
1869 | 1901 | } |
1870 | 1902 | } |
1871 | - else | |
1872 | - { | |
1873 | - v->sampPos = -1; | |
1874 | - } | |
1875 | 1903 | } |
1876 | 1904 | } |
1905 | + | |
1906 | + //smp = intp->interpSamp(v); | |
1907 | + resampler_read_pair(v->resampler[0], &s, &s); | |
1908 | + smp = s; | |
1909 | + | |
1910 | + audioMainR += (smp * v->gainRight) >> 8; | |
1911 | + audioMainL += (smp * v->gainLeft) >> 8; | |
1912 | + audioDelayR += (smp * v->gainDelayRight) >> 8; | |
1913 | + audioDelayL += (smp * v->gainDelayLeft) >> 8; | |
1877 | 1914 | } |
1878 | 1915 | } |
1879 | 1916 | else |
1880 | 1917 | { |
1881 | 1918 | //interpolation |
1882 | 1919 | //smp = intp->interpSynt(v); |
1883 | - smp = v->waveBuff[v->synthPos>>8]; | |
1920 | + sample_t s; | |
1921 | + while ( resampler_get_min_fill(v->resampler[0]) ) | |
1922 | + { | |
1923 | + s = v->waveBuff[v->synthPos]; | |
1924 | + resampler_write_pair(v->resampler[0], s, s); | |
1925 | + v->synthPos++; | |
1926 | + v->synthPos &= v->wavelength; | |
1927 | + } | |
1928 | + resampler_read_pair(v->resampler[0], &s, &s); | |
1929 | + smp = s; | |
1884 | 1930 | |
1885 | 1931 | audioMainR += (smp * v->gainRight) >> 8; |
1886 | 1932 | audioMainL += (smp * v->gainLeft) >> 8; |
1887 | 1933 | audioDelayR += (smp * v->gainDelayRight) >> 8; |
1888 | 1934 | audioDelayL += (smp * v->gainDelayLeft) >> 8; |
1889 | - v->synthPos += v->delta; | |
1890 | - v->synthPos &= v->wavelength; | |
1891 | 1935 | } |
1892 | 1936 | } |
1893 | 1937 | } |
1894 | 1938 | |
@@ -1938,9 +1982,13 @@ | ||
1938 | 1982 | } |
1939 | 1983 | if ( p->otherSamplesPerBeat == (p->samplesPerBeat * p->SAMPLEFREQUENCY) / 44100 ) |
1940 | 1984 | { |
1941 | 1985 | p->bkpDelayPos = p->delayPos; |
1942 | - for (i = 0; i < p->channelNumber; i++) p->voices[i].bkpSynthPos = p->voices[i].synthPos; | |
1986 | + for (i = 0; i < p->channelNumber; i++) | |
1987 | + { | |
1988 | + p->voices[i].bkpSynthPos = p->voices[i].synthPos; | |
1989 | + resampler_dup_inplace(p->voices[i].resampler[1], p->voices[i].resampler[0]); | |
1990 | + } | |
1943 | 1991 | |
1944 | 1992 | p->overlapPos = 0; |
1945 | 1993 | if ( outBuff ) |
1946 | 1994 | { |
@@ -1956,65 +2004,79 @@ | ||
1956 | 2004 | { |
1957 | 2005 | v = &p->voices[j]; |
1958 | 2006 | if ( v->isSample == 1 ) |
1959 | 2007 | { |
1960 | - if ( v->sampPos != -1 ) | |
2008 | + if ( v->sampPos != -1 || resampler_get_avail(v->resampler[1]) ) | |
1961 | 2009 | { |
1962 | 2010 | //interpolation |
1963 | 2011 | //smp = intp->interpSamp(v); |
1964 | - smp = v->waveBuff[v->sampPos>>8]; | |
1965 | - | |
1966 | - audioMainR += (smp * v->gainRight) >> 8; | |
1967 | - audioMainL += (smp * v->gainLeft) >> 8; | |
1968 | - audioDelayR += (smp * v->gainDelayRight) >> 8; | |
1969 | - audioDelayL += (smp * v->gainDelayLeft) >> 8; | |
1970 | - if ( v->isPlayingBackward ) | |
2012 | + sample_t s; | |
2013 | + while ( v->sampPos != -1 && resampler_get_min_fill(v->resampler[1]) ) | |
1971 | 2014 | { |
1972 | - v->sampPos -= v->delta; | |
1973 | - if ( v->sampPos <= v->smpLoopStart ) | |
2015 | + s = v->waveBuff[v->sampPos]; | |
2016 | + resampler_write_pair(v->resampler[1], s, s); | |
2017 | + if ( v->isPlayingBackward ) | |
1974 | 2018 | { |
1975 | - v->isPlayingBackward = 0; | |
1976 | - v->sampPos += v->delta; | |
2019 | + v->sampPos--; | |
2020 | + if ( v->sampPos <= v->smpLoopStart ) | |
2021 | + { | |
2022 | + v->isPlayingBackward = 0; | |
2023 | + v->sampPos++; | |
2024 | + } | |
1977 | 2025 | } |
1978 | - } | |
1979 | - else | |
1980 | - { | |
1981 | - v->sampPos += v->delta; | |
1982 | - if ( v->sampPos >= v->smpLoopEnd ) | |
2026 | + else | |
1983 | 2027 | { |
1984 | - if ( v->hasLoop ) | |
2028 | + v->sampPos++; | |
2029 | + if ( v->sampPos >= v->smpLoopEnd ) | |
1985 | 2030 | { |
1986 | - v->hasLooped = 1; | |
1987 | - if ( v->hasBidiLoop ) | |
2031 | + if ( v->hasLoop ) | |
1988 | 2032 | { |
1989 | - v->isPlayingBackward = 1; | |
1990 | - v->sampPos -= v->delta; | |
2033 | + v->hasLooped = 1; | |
2034 | + if ( v->hasBidiLoop ) | |
2035 | + { | |
2036 | + v->isPlayingBackward = 1; | |
2037 | + v->sampPos--; | |
2038 | + } | |
2039 | + else | |
2040 | + { | |
2041 | + v->sampPos += v->smpLoopStart - v->smpLoopEnd; | |
2042 | + } | |
1991 | 2043 | } |
1992 | 2044 | else |
1993 | 2045 | { |
1994 | - v->sampPos += v->smpLoopStart - v->smpLoopEnd; | |
2046 | + v->sampPos = -1; | |
1995 | 2047 | } |
1996 | 2048 | } |
1997 | - else | |
1998 | - { | |
1999 | - v->sampPos = -1; | |
2000 | - } | |
2001 | 2049 | } |
2002 | 2050 | } |
2051 | + resampler_read_pair(v->resampler[1], &s, &s); | |
2052 | + smp = s; | |
2053 | + | |
2054 | + audioMainR += (smp * v->gainRight) >> 8; | |
2055 | + audioMainL += (smp * v->gainLeft) >> 8; | |
2056 | + audioDelayR += (smp * v->gainDelayRight) >> 8; | |
2057 | + audioDelayL += (smp * v->gainDelayLeft) >> 8; | |
2003 | 2058 | } |
2004 | 2059 | } |
2005 | 2060 | else |
2006 | 2061 | { |
2007 | 2062 | //interpolation |
2008 | 2063 | //smp = intp->interpSynt(v); |
2009 | - smp = v->waveBuff[v->synthPos>>8]; | |
2064 | + sample_t s; | |
2065 | + while ( resampler_get_min_fill(v->resampler[1]) ) | |
2066 | + { | |
2067 | + s = v->waveBuff[v->synthPos]; | |
2068 | + resampler_write_pair(v->resampler[1], s, s); | |
2069 | + v->synthPos++; | |
2070 | + v->synthPos &= v->wavelength; | |
2071 | + } | |
2072 | + resampler_read_pair(v->resampler[1], &s, &s); | |
2073 | + smp = s; | |
2010 | 2074 | |
2011 | 2075 | audioMainR += (smp * v->gainRight) >> 8; |
2012 | 2076 | audioMainL += (smp * v->gainLeft) >> 8; |
2013 | 2077 | audioDelayR += (smp * v->gainDelayRight) >> 8; |
2014 | 2078 | audioDelayL += (smp * v->gainDelayLeft) >> 8; |
2015 | - v->synthPos += v->delta; | |
2016 | - v->synthPos &= v->wavelength; | |
2017 | 2079 | } |
2018 | 2080 | } |
2019 | 2081 | } |
2020 | 2082 |
src/syntrax/syntrax.h | ||
---|---|---|
@@ -1,10 +1,8 @@ | ||
1 | 1 | |
2 | 2 | |
3 | 3 | |
4 | 4 | |
5 | - | |
6 | - | |
7 | 5 | |
8 | 6 | //----------------------------typedefs------------------------- |
9 | 7 | |
10 | 8 | |
@@ -58,8 +56,10 @@ | ||
58 | 56 | int smpLength; |
59 | 57 | int gainDelayRight; |
60 | 58 | int gainDelayLeft; |
61 | 59 | int hasLooped; |
60 | + void * resampler[2]; | |
61 | + int last_delta; | |
62 | 62 | } Voice; |
63 | 63 | |
64 | 64 | typedef struct |
65 | 65 | { |
src/syntrax/resampler.c | ||
---|---|---|
@@ -1,0 +1,361 @@ | ||
1 | + | |
2 | + | |
3 | + | |
4 | + | |
5 | + | |
6 | + | |
7 | +/* Copyright (C) 2004-2008 Shay Green. | |
8 | + Copyright (C) 2015 Christopher Snowhill. This module is free software; you | |
9 | +can redistribute it and/or modify it under the terms of the GNU Lesser | |
10 | +General Public License as published by the Free Software Foundation; either | |
11 | +version 2.1 of the License, or (at your option) any later version. This | |
12 | +module is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
14 | +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | |
15 | +details. You should have received a copy of the GNU Lesser General Public | |
16 | +License along with this module; if not, write to the Free Software Foundation, | |
17 | +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |
18 | + | |
19 | + | |
20 | + | |
21 | + | |
22 | +enum { imp_scale = 0x7FFF }; | |
23 | +typedef int16_t imp_t; | |
24 | +typedef int32_t imp_off_t; /* for max_res of 512 and impulse width of 32, end offsets must be 32 bits */ | |
25 | + | |
26 | + | |
27 | +typedef int32_t intermediate_t; | |
28 | + | |
29 | +typedef int64_t intermediate_t; | |
30 | + | |
31 | + | |
32 | +static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale, | |
33 | + int count, imp_t* out ) | |
34 | +{ | |
35 | + double const maxh = 256; | |
36 | + double const step = PI / maxh * spacing; | |
37 | + double const to_w = maxh * 2 / width; | |
38 | + double const pow_a_n = pow( rolloff, maxh ); | |
39 | + scale /= maxh * 2; | |
40 | + double angle = (count / 2 - 1 + offset) * -step; | |
41 | + | |
42 | + while ( count-- ) | |
43 | + { | |
44 | + *out++ = 0; | |
45 | + double w = angle * to_w; | |
46 | + if ( fabs( w ) < PI ) | |
47 | + { | |
48 | + double rolloff_cos_a = rolloff * cos( angle ); | |
49 | + double num = 1 - rolloff_cos_a - | |
50 | + pow_a_n * cos( maxh * angle ) + | |
51 | + pow_a_n * rolloff * cos( (maxh - 1) * angle ); | |
52 | + double den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; | |
53 | + double sinc = scale * num / den - scale; | |
54 | + | |
55 | + out [-1] = (imp_t) (cos( w ) * sinc + sinc); | |
56 | + } | |
57 | + angle += step; | |
58 | + } | |
59 | +} | |
60 | + | |
61 | +enum { width = 32 }; | |
62 | +enum { stereo = 2 }; | |
63 | +enum { max_res = 512 }; | |
64 | +enum { min_width = (width < 4 ? 4 : width) }; | |
65 | +enum { adj_width = min_width / 4 * 4 + 2 }; | |
66 | +enum { write_offset = adj_width * stereo }; | |
67 | + | |
68 | +enum { buffer_size = 128 }; | |
69 | + | |
70 | +typedef struct _resampler | |
71 | +{ | |
72 | + int width_; | |
73 | + int rate_; | |
74 | + int inptr; | |
75 | + int infilled; | |
76 | + int outptr; | |
77 | + int outfilled; | |
78 | + | |
79 | + int latency; | |
80 | + | |
81 | + imp_t const* imp; | |
82 | + imp_t impulses [max_res * (adj_width + 2 * (sizeof(imp_off_t) / sizeof(imp_t)))]; | |
83 | + sample_t buffer_in[buffer_size * stereo * 2]; | |
84 | + sample_t buffer_out[buffer_size * stereo]; | |
85 | +} resampler; | |
86 | + | |
87 | +void * resampler_create() | |
88 | +{ | |
89 | + resampler *r = (resampler *) malloc(sizeof(resampler)); | |
90 | + if (r) resampler_clear(r); | |
91 | + return r; | |
92 | +} | |
93 | + | |
94 | +void * resampler_dup(const void *_r) | |
95 | +{ | |
96 | + void *_t = (resampler *) malloc(sizeof(resampler)); | |
97 | + if (_t) resampler_dup_inplace(_t, _r); | |
98 | + return _t; | |
99 | +} | |
100 | + | |
101 | +void resampler_dup_inplace(void *_t, const void *_r) | |
102 | +{ | |
103 | + const resampler *r = (const resampler *)_r; | |
104 | + resampler *t = (resampler *)_t; | |
105 | + if (r && t) | |
106 | + { | |
107 | + memcpy(t, r, sizeof(resampler)); | |
108 | + t->imp = t->impulses + (r->imp - r->impulses); | |
109 | + } | |
110 | + else if (t) | |
111 | + { | |
112 | + resampler_clear(t); | |
113 | + } | |
114 | +} | |
115 | + | |
116 | +void resampler_destroy(void *r) | |
117 | +{ | |
118 | + free(r); | |
119 | +} | |
120 | + | |
121 | +void resampler_clear(void *_r) | |
122 | +{ | |
123 | + resampler * r = (resampler *)_r; | |
124 | + r->width_ = adj_width; | |
125 | + r->inptr = 0; | |
126 | + r->infilled = 0; | |
127 | + r->outptr = 0; | |
128 | + r->outfilled = 0; | |
129 | + r->latency = 0; | |
130 | + r->imp = r->impulses; | |
131 | + | |
132 | + resampler_set_rate(r, 1.0); | |
133 | +} | |
134 | + | |
135 | +void resampler_set_rate( void *_r, double new_factor ) | |
136 | +{ | |
137 | + resampler *rs = (resampler *)_r; | |
138 | + | |
139 | + double const rolloff = 0.999; | |
140 | + double const gain = 1.0; | |
141 | + | |
142 | + /* determine number of sub-phases that yield lowest error */ | |
143 | + double ratio_ = 0.0; | |
144 | + int res = -1; | |
145 | + { | |
146 | + double least_error = 2; | |
147 | + double pos = 0; | |
148 | + for ( int r = 1; r <= max_res; r++ ) | |
149 | + { | |
150 | + pos += new_factor; | |
151 | + double nearest = floor( pos + 0.5 ); | |
152 | + double error = fabs( pos - nearest ); | |
153 | + if ( error < least_error ) | |
154 | + { | |
155 | + res = r; | |
156 | + ratio_ = nearest / res; | |
157 | + least_error = error; | |
158 | + } | |
159 | + } | |
160 | + } | |
161 | + rs->rate_ = ratio_; | |
162 | + | |
163 | + /* how much of input is used for each output sample */ | |
164 | + int const step = stereo * (int) floor( ratio_ ); | |
165 | + double fraction = fmod( ratio_, 1.0 ); | |
166 | + | |
167 | + double const filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_; | |
168 | + double pos = 0.0; | |
169 | + /*int input_per_cycle = 0;*/ | |
170 | + imp_t* out = rs->impulses; | |
171 | + for ( int n = res; --n >= 0; ) | |
172 | + { | |
173 | + gen_sinc( rolloff, (int) (rs->width_ * filter + 1) & ~1, pos, filter, | |
174 | + (double)(imp_scale * gain * filter), (int) rs->width_, out ); | |
175 | + out += rs->width_; | |
176 | + | |
177 | + int cur_step = step; | |
178 | + pos += fraction; | |
179 | + if ( pos >= 0.9999999 ) | |
180 | + { | |
181 | + pos -= 1.0; | |
182 | + cur_step += stereo; | |
183 | + } | |
184 | + | |
185 | + ((imp_off_t*)out)[0] = (cur_step - rs->width_ * 2 + 4) * sizeof (sample_t); | |
186 | + ((imp_off_t*)out)[1] = 2 * sizeof (imp_t) + 2 * sizeof (imp_off_t); | |
187 | + out += 2 * (sizeof(imp_off_t) / sizeof(imp_t)); | |
188 | + /*input_per_cycle += cur_step;*/ | |
189 | + } | |
190 | + /* last offset moves back to beginning of impulses*/ | |
191 | + ((imp_off_t*)out) [-1] -= (char*) out - (char*) rs->impulses; | |
192 | + | |
193 | + rs->imp = rs->impulses; | |
194 | +} | |
195 | + | |
196 | +int resampler_get_free(void *_r) | |
197 | +{ | |
198 | + resampler *r = (resampler *)_r; | |
199 | + return buffer_size * stereo - r->infilled; | |
200 | +} | |
201 | + | |
202 | +int resampler_get_min_fill(void *_r) | |
203 | +{ | |
204 | + resampler *r = (resampler *)_r; | |
205 | + const int min_needed = write_offset + stereo; | |
206 | + const int latency = r->latency ? 0 : adj_width; | |
207 | + int min_free = min_needed - r->infilled - latency; | |
208 | + return min_free < 0 ? 0 : min_free; | |
209 | +} | |
210 | + | |
211 | +void resampler_write_pair(void *_r, sample_t ls, sample_t rs) | |
212 | +{ | |
213 | + resampler *r = (resampler *)_r; | |
214 | + | |
215 | + if (!r->latency) | |
216 | + { | |
217 | + for (int i = 0; i < adj_width / 2; ++i) | |
218 | + { | |
219 | + r->buffer_in[r->inptr + 0] = 0; | |
220 | + r->buffer_in[r->inptr + 1] = 0; | |
221 | + r->buffer_in[buffer_size * stereo + r->inptr + 0] = 0; | |
222 | + r->buffer_in[buffer_size * stereo + r->inptr + 1] = 0; | |
223 | + r->inptr = (r->inptr + stereo) % (buffer_size * stereo); | |
224 | + r->infilled += stereo; | |
225 | + } | |
226 | + r->latency = 1; | |
227 | + } | |
228 | + | |
229 | + if (r->infilled < buffer_size * stereo) | |
230 | + { | |
231 | + r->buffer_in[r->inptr + 0] = ls; | |
232 | + r->buffer_in[r->inptr + 1] = rs; | |
233 | + r->buffer_in[buffer_size * stereo + r->inptr + 0] = ls; | |
234 | + r->buffer_in[buffer_size * stereo + r->inptr + 1] = rs; | |
235 | + r->inptr = (r->inptr + stereo) % (buffer_size * stereo); | |
236 | + r->infilled += stereo; | |
237 | + } | |
238 | +} | |
239 | + | |
240 | + | |
241 | + | |
242 | + | |
243 | + | |
244 | +static const sample_t * resampler_inner_loop( resampler *r, sample_t** out_, | |
245 | + sample_t const* out_end, sample_t const in [], int in_size ) | |
246 | +{ | |
247 | + in_size -= write_offset; | |
248 | + if ( in_size > 0 ) | |
249 | + { | |
250 | + sample_t* restrict out = *out_; | |
251 | + sample_t const* const in_end = in + in_size; | |
252 | + imp_t const* imp = r->imp; | |
253 | + | |
254 | + do | |
255 | + { | |
256 | + /* accumulate in extended precision*/ | |
257 | + int pt = imp [0]; | |
258 | + intermediate_t l = (intermediate_t)pt * (intermediate_t)(in [0]); | |
259 | + intermediate_t r = (intermediate_t)pt * (intermediate_t)(in [1]); | |
260 | + if ( out >= out_end ) | |
261 | + break; | |
262 | + for ( int n = (adj_width - 2) / 2; n; --n ) | |
263 | + { | |
264 | + pt = imp [1]; | |
265 | + l += (intermediate_t)pt * (intermediate_t)(in [2]); | |
266 | + r += (intermediate_t)pt * (intermediate_t)(in [3]); | |
267 | + | |
268 | + /* pre-increment more efficient on some RISC processors*/ | |
269 | + imp += 2; | |
270 | + pt = imp [0]; | |
271 | + r += (intermediate_t)pt * (intermediate_t)(in [5]); | |
272 | + in += 4; | |
273 | + l += (intermediate_t)pt * (intermediate_t)(in [0]); | |
274 | + } | |
275 | + pt = imp [1]; | |
276 | + l += (intermediate_t)pt * (intermediate_t)(in [2]); | |
277 | + r += (intermediate_t)pt * (intermediate_t)(in [3]); | |
278 | + | |
279 | + /* these two "samples" after the end of the impulse give the | |
280 | + * proper offsets to the next input sample and next impulse */ | |
281 | + in = (sample_t const*) ((char const*) in + ((imp_off_t*)(&imp [2]))[0]); /* some negative value */ | |
282 | + imp = (imp_t const*) ((char const*) imp + ((imp_off_t*)(&imp [2]))[1]); /* small positive or large negative */ | |
283 | + | |
284 | + out [0] = (sample_t) (l >> 15); | |
285 | + out [1] = (sample_t) (r >> 15); | |
286 | + out += 2; | |
287 | + } | |
288 | + while ( in < in_end ); | |
289 | + | |
290 | + r->imp = imp; | |
291 | + *out_ = out; | |
292 | + } | |
293 | + return in; | |
294 | +} | |
295 | + | |
296 | + | |
297 | + | |
298 | +static int resampler_wrapper( resampler *r, sample_t out [], int* out_size, | |
299 | + sample_t const in [], int in_size ) | |
300 | +{ | |
301 | + sample_t* out_ = out; | |
302 | + int result = resampler_inner_loop( r, &out_, out + *out_size, in, in_size ) - in; | |
303 | + | |
304 | + *out_size = out_ - out; | |
305 | + return result; | |
306 | +} | |
307 | + | |
308 | +static void resampler_fill( resampler *r ) | |
309 | +{ | |
310 | + while (!r->outfilled && r->infilled) | |
311 | + { | |
312 | + int writepos = ( r->outptr + r->outfilled ) % (buffer_size * stereo); | |
313 | + int writesize = (buffer_size * stereo) - writepos; | |
314 | + if ( writesize > ( buffer_size * stereo - r->outfilled ) ) | |
315 | + writesize = buffer_size * stereo - r->outfilled; | |
316 | + int inread = resampler_wrapper(r, &r->buffer_out[writepos], &writesize, &r->buffer_in[buffer_size * stereo + r->inptr - r->infilled], r->infilled); | |
317 | + r->infilled -= inread; | |
318 | + r->outfilled += writesize; | |
319 | + if (!inread) | |
320 | + break; | |
321 | + } | |
322 | +} | |
323 | + | |
324 | +int resampler_get_avail(void *_r) | |
325 | +{ | |
326 | + resampler *r = (resampler *)_r; | |
327 | + if (r->outfilled < stereo && r->infilled >= r->width_) | |
328 | + resampler_fill( r ); | |
329 | + return r->outfilled; | |
330 | +} | |
331 | + | |
332 | +static void resampler_read_pair_internal( resampler *r, sample_t *ls, sample_t *rs, int advance ) | |
333 | +{ | |
334 | + if (r->outfilled < stereo) | |
335 | + resampler_fill( r ); | |
336 | + if (r->outfilled < stereo) | |
337 | + { | |
338 | + *ls = 0; | |
339 | + *rs = 0; | |
340 | + return; | |
341 | + } | |
342 | + *ls = r->buffer_out[r->outptr + 0]; | |
343 | + *rs = r->buffer_out[r->outptr + 1]; | |
344 | + if (advance) | |
345 | + { | |
346 | + r->outptr = (r->outptr + 2) % (buffer_size * stereo); | |
347 | + r->outfilled -= stereo; | |
348 | + } | |
349 | +} | |
350 | + | |
351 | +void resampler_read_pair( void *_r, sample_t *ls, sample_t *rs ) | |
352 | +{ | |
353 | + resampler *r = (resampler *)_r; | |
354 | + resampler_read_pair_internal(r, ls, rs, 1); | |
355 | +} | |
356 | + | |
357 | +void resampler_peek_pair( void *_r, sample_t *ls, sample_t *rs ) | |
358 | +{ | |
359 | + resampler *r = (resampler *)_r; | |
360 | + resampler_read_pair_internal(r, ls, rs, 0); | |
361 | +} |
src/syntrax/resampler.h | ||
---|---|---|
@@ -1,0 +1,75 @@ | ||
1 | + | |
2 | + | |
3 | + | |
4 | +/* Copyright (C) 2004-2008 Shay Green. | |
5 | + Copyright (C) 2015 Christopher Snowhill. This module is free software; you | |
6 | +can redistribute it and/or modify it under the terms of the GNU Lesser | |
7 | +General Public License as published by the Free Software Foundation; either | |
8 | +version 2.1 of the License, or (at your option) any later version. This | |
9 | +module is distributed in the hope that it will be useful, but WITHOUT ANY | |
10 | +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
11 | +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | |
12 | +details. You should have received a copy of the GNU Lesser General Public | |
13 | +License along with this module; if not, write to the Free Software Foundation, | |
14 | +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |
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 | +typedef int16_t sample_t; | |
42 | + | |
43 | +typedef int32_t sample_t; | |
44 | + | |
45 | + | |
46 | + | |
47 | + | |
48 | + | |
49 | +extern "C" { | |
50 | + | |
51 | + | |
52 | +void * resampler_create(); | |
53 | +void * resampler_dup(const void *); | |
54 | +void resampler_dup_inplace(void *, const void *); | |
55 | +void resampler_destroy(void *); | |
56 | + | |
57 | +void resampler_clear(void *); | |
58 | + | |
59 | +void resampler_set_rate( void *, double new_factor ); | |
60 | + | |
61 | +int resampler_get_free(void *); | |
62 | +int resampler_get_min_fill(void *); | |
63 | + | |
64 | +void resampler_write_pair(void *, sample_t ls, sample_t rs); | |
65 | + | |
66 | +int resampler_get_avail(void *); | |
67 | + | |
68 | +void resampler_read_pair( void *, sample_t *ls, sample_t *rs ); | |
69 | +void resampler_peek_pair( void *, sample_t *ls, sample_t *rs ); | |
70 | + | |
71 | + | |
72 | +} | |
73 | + | |
74 | + | |
75 | + |
Built with git-ssb-web