LibXenon
Bare-metal Xbox 360 homebrew library
Loading...
Searching...
No Matches
sound.c
Go to the documentation of this file.
1#include <pci/io.h>
2#include <stdint.h>
3#include <string.h>
6#include <ppc/cache.h>
7
8extern int xenos_is_hdmi;
9
10static int snd_base = 0xea001600, wptr, buffer_len;
11
12// those 2 must be in the first 32MB of physical memory it seems...
13static uint8_t buffer[65536] __attribute__ ((section(".bss.beginning.lower"),aligned (256)));
14static uint32_t descr[0x20*2] __attribute__ ((section(".bss.beginning.lower"),aligned (256)));
15
17{
18 // reset DAC (init from scratch)
19 xenon_gpio_control(5,0x1000,0x1000);
20 xenon_gpio_control(0,0x1000,0x1000);
21 xenon_gpio_control(4,0x1000,0x1000);
22
23 if(xenos_is_hdmi){
24 // HDMI audio enable
25 xenon_smc_i2c_write(0x0214, 0x11);
26 xenon_smc_i2c_write(0x0202, 0x03);
27 xenon_smc_i2c_write(0x0203, 0x00);
28 xenon_smc_i2c_write(0x0204, 0x18);
29 xenon_smc_i2c_write(0x0205, 0x00);
30 xenon_smc_i2c_write(0x021d, 0x40);
31 xenon_smc_i2c_write(0x0221, 0x02);
32 xenon_smc_i2c_write(0x0222, 0x2b);
33
34 xenon_smc_i2c_write(0x022f,0x01);
35 xenon_smc_i2c_write(0x023e,0x3f);
36
37 xenon_smc_i2c_write(0x02df,0x10);// Av mute ?
38 }
39
40 static unsigned char smc_snd[32] = {0x8d, 1, 1};
42
43 unsigned int descr_base = ((unsigned int)descr) & 0x1fffffff;
44
45 buffer_len = sizeof(buffer);
46 memset(buffer, 0, buffer_len);
47 memdcbst(buffer, buffer_len);
48
49 unsigned int buffer_base = ((unsigned int)buffer) & 0x1fffffff;
50
51 int i;
52 for (i = 0; i < 0x20; ++i)
53 {
54 descr[i * 2] = __builtin_bswap32(buffer_base + (buffer_len/0x20) * i);
55 descr[i * 2 + 1] = __builtin_bswap32(0x80000000 | (buffer_len/0x20));
56 }
57
58 memdcbf(descr, sizeof(descr));
59
60 write32(snd_base + 8, 0);
61 write32(snd_base + 8, 0x2000000);
62 write32(snd_base + 0, descr_base);
63 write32(snd_base + 8, 0x1d08001c);
64 write32(snd_base + 0xC, 0x1c);
65
66 wptr = 0;
67}
68
69void xenon_sound_submit(void *data, int len)
70{
71 int i = 0;
72 while (len)
73 {
74 int av = buffer_len - wptr;
75 if (av > len)
76 av = len;
77
78 memcpy(buffer + wptr, data + i, av);
79 memdcbst(buffer + wptr, av);
80
81 i += av;
82 wptr += av;
83 len -= av;
84 if (wptr == buffer_len)
85 wptr = 0;
86 }
87 int cur_descr = (wptr / (buffer_len/0x20) -1) & 0x1f;
88
89 write32(snd_base + 4, cur_descr << 8);
90 write32(snd_base + 8, read32(snd_base) | 0x1000000);
91}
92
94{
95 uint32_t reg = read32(snd_base + 4);
96
97 int rptr_descr = reg & 0x1f;
98 int last_valid_descr = (reg & 0x1f00) >> 8;
99 int cur_len = (reg >> 16) & 0xFFFF;
100
101 if (rptr_descr == last_valid_descr && !cur_len)
102 return buffer_len;
103
104 int rptr = rptr_descr * (buffer_len/0x20);
105 int av = rptr - wptr;
106 if (av < 0)
107 av += buffer_len;
108 return av;
109}
110
112{
113 uint32_t reg = read32(snd_base + 4);
114
115 int rptr_descr = reg & 0x1f;
116 int last_valid_descr = (reg & 0x1f00) >> 8;
117 int cur_len = (reg >> 16) & 0xFFFF;
118
119 int l = last_valid_descr - rptr_descr;
120 if (l < 0)
121 l += 0x20;
122 l *= (buffer_len/0x20);
123 l += cur_len;
124
125 return l;
126}
127
128void xenon_tone(uint32_t frequency, uint32_t duration, int16_t amplitude)
129{
130 uint8_t pcm_data[1024];
131
132 // xenon assumes a 48kHz sample rate for submitted audio data
133 const uint32_t sample_rate = 48000;
134
135 uint32_t phase = 0;
136 uint32_t phase_step = (uint32_t)(((uint64_t)frequency << 32) / sample_rate);
137
138 const uint32_t bytes_per_frame = sizeof(int16_t) * 2;
139 const uint32_t total_frames = (sample_rate * duration) / 1000;
140 uint32_t frames_remaining = total_frames;
141
142 while (frames_remaining)
143 {
144 uint32_t i;
145 uint32_t chunk_frames = sizeof(pcm_data) / bytes_per_frame;
146
147 if (chunk_frames > frames_remaining)
148 chunk_frames = frames_remaining;
149
150 for (i = 0; i < chunk_frames; ++i)
151 {
152 // 50% duty square wave
153 int16_t v = (phase & 0x80000000U) ? -amplitude : amplitude;
154 uint16_t le = (uint16_t)v;
155 uint32_t o = i * bytes_per_frame;
156
157 // Write little-endian 16-bit stereo PCM
158 pcm_data[o + 0] = le & 0xFF;
159 pcm_data[o + 1] = (le >> 8) & 0xFF;
160 pcm_data[o + 2] = le & 0xFF;
161 pcm_data[o + 3] = (le >> 8) & 0xFF;
162
163 phase += phase_step;
164 }
165
166 while (xenon_sound_get_unplayed() >= 32768);
167
168 xenon_sound_submit(pcm_data, sizeof(pcm_data));
169 frames_remaining -= chunk_frames;
170 }
171}
void memdcbf(void *addr, int len)
void memdcbst(void *addr, int len)
u32 uint32_t
Definition: libfdt_env.h:11
s16 int16_t
Definition: libfdt_env.h:15
u16 uint16_t
Definition: libfdt_env.h:10
u64 uint64_t
Definition: libfdt_env.h:12
u8 uint8_t
Definition: libfdt_env.h:9
unsigned int __mf_uintptr_t __attribute__((__mode__(__pointer__)))
Definition: mf-runtime.h:34
void xenon_tone(uint32_t frequency, uint32_t duration, int16_t amplitude)
Definition: sound.c:128
int xenon_sound_get_free(void)
Definition: sound.c:93
void xenon_sound_init(void)
Definition: sound.c:16
int xenos_is_hdmi
Definition: xenos.c:22
void xenon_sound_submit(void *data, int len)
Definition: sound.c:69
int xenon_sound_get_unplayed(void)
Definition: sound.c:111
void xenon_gpio_control(uint32_t reg, uint32_t clear, uint32_t set)
Definition: xenon_gpio.c:6
void xenon_smc_send_message(const unsigned char *msg)
Definition: xenon_smc.c:20
int xenon_smc_i2c_write(uint16_t addr, uint8_t val)
Definition: xenon_smc.c:192
union @15 data