Skip to content

Commit 015bbdc

Browse files
committed
audio: reduce code size
By placing certain fields in a fixed location in all sample types, code can be reduced & reused. For instance, the same property object can be used for every sample type's `sample_rate` property. The sample proto functions like `sample_rate` become superfluous since once an object is verified to support the audiosample protocol, direct access to the fields in the base object is possible.
1 parent 469e88d commit 015bbdc

File tree

45 files changed

+369
-816
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+369
-816
lines changed

ports/atmel-samd/audio_dma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
251251
}
252252

253253

254-
if (audiosample_bits_per_sample(sample) == 16) {
254+
if (audiosample_get_bits_per_sample(sample) == 16) {
255255
dma->beat_size = 2;
256256
dma->bytes_per_sample = 2;
257257
} else {
@@ -262,7 +262,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
262262
}
263263
}
264264
// Transfer both channels at once.
265-
if (!single_channel_output && audiosample_channel_count(sample) == 2) {
265+
if (!single_channel_output && audiosample_get_channel_count(sample) == 2) {
266266
dma->beat_size *= 2;
267267
}
268268

ports/atmel-samd/audio_dma.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "py/obj.h"
1111
#include "shared-module/audiocore/RawSample.h"
1212
#include "shared-module/audiocore/WaveFile.h"
13+
#include "shared-module/audiocore/__init__.h"
1314
#include "supervisor/background_callback.h"
1415

1516
typedef struct {
@@ -40,10 +41,6 @@ typedef enum {
4041
AUDIO_DMA_MEMORY_ERROR,
4142
} audio_dma_result;
4243

43-
uint32_t audiosample_sample_rate(mp_obj_t sample_obj);
44-
uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj);
45-
uint8_t audiosample_channel_count(mp_obj_t sample_obj);
46-
4744
void audio_dma_init(audio_dma_t *dma);
4845
void audio_dma_reset(void);
4946

ports/atmel-samd/common-hal/audioio/AudioOut.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
333333
common_hal_audioio_audioout_stop(self);
334334
}
335335
audio_dma_result result = AUDIO_DMA_OK;
336-
uint32_t sample_rate = audiosample_sample_rate(sample);
336+
uint32_t sample_rate = audiosample_get_sample_rate(sample);
337337
#ifdef SAMD21
338338
const uint32_t max_sample_rate = 350000;
339339
#endif
@@ -364,12 +364,12 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
364364
right_channel_reg = (uint32_t)&DAC->DATABUF[0].reg;
365365
}
366366

367-
size_t num_channels = audiosample_channel_count(sample);
367+
size_t num_channels = audiosample_get_channel_count(sample);
368368

369369
if (num_channels == 2 &&
370370
// Are DAC channels sequential?
371371
left_channel_reg + 2 == right_channel_reg &&
372-
audiosample_bits_per_sample(sample) == 16) {
372+
audiosample_get_bits_per_sample(sample) == 16) {
373373
result = audio_dma_setup_playback(&self->left_dma, sample, loop, false, 0,
374374
false /* output unsigned */,
375375
left_channel_reg,
@@ -403,7 +403,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
403403
}
404404
}
405405
Tc *timer = tc_insts[self->tc_index];
406-
set_timer_frequency(timer, audiosample_sample_rate(sample));
406+
set_timer_frequency(timer, audiosample_get_sample_rate(sample));
407407
timer->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
408408
while (timer->COUNT16.STATUS.bit.STOP == 1) {
409409
}

ports/raspberrypi/audio_dma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ audio_dma_result audio_dma_setup_playback(
203203
dma->output_signed = output_signed;
204204
dma->sample_spacing = 1;
205205
dma->output_resolution = output_resolution;
206-
dma->sample_resolution = audiosample_bits_per_sample(sample);
206+
dma->sample_resolution = audiosample_get_bits_per_sample(sample);
207207
dma->output_register_address = output_register_address;
208208
dma->swap_channel = swap_channel;
209209

@@ -250,7 +250,7 @@ audio_dma_result audio_dma_setup_playback(
250250
dma->output_size = 1;
251251
}
252252
// Transfer both channels at once.
253-
if (!single_channel_output && audiosample_channel_count(sample) == 2) {
253+
if (!single_channel_output && audiosample_get_channel_count(sample) == 2) {
254254
dma->output_size *= 2;
255255
}
256256
enum dma_channel_transfer_size dma_size = DMA_SIZE_8;

ports/raspberrypi/common-hal/audiobusio/I2SOut.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self,
232232
common_hal_audiobusio_i2sout_stop(self);
233233
}
234234

235-
uint8_t bits_per_sample = audiosample_bits_per_sample(sample);
235+
uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample);
236236
// Make sure we transmit a minimum of 16 bits.
237237
// TODO: Maybe we need an intermediate object to upsample instead. This is
238238
// only needed for some I2S devices that expect at least 8.
@@ -242,8 +242,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self,
242242
// We always output stereo so output twice as many bits.
243243
uint16_t bits_per_sample_output = bits_per_sample * 2;
244244
size_t clocks_per_bit = 6;
245-
uint32_t frequency = bits_per_sample_output * audiosample_sample_rate(sample);
246-
uint8_t channel_count = audiosample_channel_count(sample);
245+
uint32_t frequency = bits_per_sample_output * audiosample_get_sample_rate(sample);
246+
uint8_t channel_count = audiosample_get_channel_count(sample);
247247
if (channel_count > 2) {
248248
mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample."));
249249
}

ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self,
187187
// to trigger the DMA. Each has a 16 bit fractional divisor system clock * X / Y where X and Y
188188
// are 16-bit.
189189

190-
uint32_t sample_rate = audiosample_sample_rate(sample);
190+
uint32_t sample_rate = audiosample_get_sample_rate(sample);
191191

192192
uint32_t system_clock = common_hal_mcu_processor_get_frequency();
193193
uint32_t best_denominator;

shared-bindings/audiocore/RawSample.c

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "py/runtime.h"
1313
#include "shared-bindings/util.h"
1414
#include "shared-bindings/audiocore/RawSample.h"
15+
#include "shared-bindings/audiocore/__init__.h"
1516

1617
//| class RawSample:
1718
//| """A raw audio sample buffer in memory"""
@@ -120,12 +121,6 @@ static mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) {
120121
}
121122
static MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit);
122123

123-
static void check_for_deinit(audioio_rawsample_obj_t *self) {
124-
if (common_hal_audioio_rawsample_deinited(self)) {
125-
raise_deinited_error();
126-
}
127-
}
128-
129124
//| def __enter__(self) -> RawSample:
130125
//| """No-op used by Context Managers."""
131126
//| ...
@@ -151,24 +146,6 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4,
151146
//| change it."""
152147
//|
153148
//|
154-
static mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) {
155-
audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
156-
check_for_deinit(self);
157-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self));
158-
}
159-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate);
160-
161-
static mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
162-
audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
163-
check_for_deinit(self);
164-
common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate));
165-
return mp_const_none;
166-
}
167-
MP_DEFINE_CONST_FUN_OBJ_2(audioio_rawsample_set_sample_rate_obj, audioio_rawsample_obj_set_sample_rate);
168-
169-
MP_PROPERTY_GETSET(audioio_rawsample_sample_rate_obj,
170-
(mp_obj_t)&audioio_rawsample_get_sample_rate_obj,
171-
(mp_obj_t)&audioio_rawsample_set_sample_rate_obj);
172149

173150
static const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = {
174151
// Methods
@@ -177,18 +154,14 @@ static const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = {
177154
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_rawsample___exit___obj) },
178155

179156
// Properties
180-
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_rawsample_sample_rate_obj) },
157+
AUDIOSAMPLE_FIELDS,
181158
};
182159
static MP_DEFINE_CONST_DICT(audioio_rawsample_locals_dict, audioio_rawsample_locals_dict_table);
183160

184161
static const audiosample_p_t audioio_rawsample_proto = {
185162
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
186-
.sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_rawsample_get_sample_rate,
187-
.bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_rawsample_get_bits_per_sample,
188-
.channel_count = (audiosample_channel_count_fun)common_hal_audioio_rawsample_get_channel_count,
189163
.reset_buffer = (audiosample_reset_buffer_fun)audioio_rawsample_reset_buffer,
190164
.get_buffer = (audiosample_get_buffer_fun)audioio_rawsample_get_buffer,
191-
.get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_rawsample_get_buffer_structure,
192165
};
193166

194167
MP_DEFINE_CONST_OBJ_TYPE(

shared-bindings/audiocore/WaveFile.c

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "py/objproperty.h"
1111
#include "py/runtime.h"
1212
#include "shared-bindings/audiocore/WaveFile.h"
13+
#include "shared-bindings/audiocore/__init__.h"
1314
#include "shared-bindings/util.h"
1415
#include "extmod/vfs_posix.h"
1516

@@ -88,12 +89,6 @@ static mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) {
8889
}
8990
static MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit);
9091

91-
static void check_for_deinit(audioio_wavefile_obj_t *self) {
92-
if (common_hal_audioio_wavefile_deinited(self)) {
93-
raise_deinited_error();
94-
}
95-
}
96-
9792
//| def __enter__(self) -> WaveFile:
9893
//| """No-op used by Context Managers."""
9994
//| ...
@@ -116,50 +111,14 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4,
116111
//| """32 bit value that dictates how quickly samples are loaded into the DAC
117112
//| in Hertz (cycles per second). When the sample is looped, this can change
118113
//| the pitch output without changing the underlying sample."""
119-
static mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) {
120-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
121-
check_for_deinit(self);
122-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self));
123-
}
124-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate);
125-
126-
static mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
127-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
128-
check_for_deinit(self);
129-
common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate));
130-
return mp_const_none;
131-
}
132-
MP_DEFINE_CONST_FUN_OBJ_2(audioio_wavefile_set_sample_rate_obj, audioio_wavefile_obj_set_sample_rate);
133-
134-
MP_PROPERTY_GETSET(audioio_wavefile_sample_rate_obj,
135-
(mp_obj_t)&audioio_wavefile_get_sample_rate_obj,
136-
(mp_obj_t)&audioio_wavefile_set_sample_rate_obj);
137114

138115
//| bits_per_sample: int
139116
//| """Bits per sample. (read only)"""
140-
static mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) {
141-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
142-
check_for_deinit(self);
143-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self));
144-
}
145-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample);
146-
147-
MP_PROPERTY_GETTER(audioio_wavefile_bits_per_sample_obj,
148-
(mp_obj_t)&audioio_wavefile_get_bits_per_sample_obj);
117+
//
149118
//| channel_count: int
150119
//| """Number of audio channels. (read only)"""
151120
//|
152121
//|
153-
static mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) {
154-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
155-
check_for_deinit(self);
156-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self));
157-
}
158-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count);
159-
160-
MP_PROPERTY_GETTER(audioio_wavefile_channel_count_obj,
161-
(mp_obj_t)&audioio_wavefile_get_channel_count_obj);
162-
163122

164123
static const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = {
165124
// Methods
@@ -168,20 +127,14 @@ static const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = {
168127
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_wavefile___exit___obj) },
169128

170129
// Properties
171-
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_wavefile_sample_rate_obj) },
172-
{ MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audioio_wavefile_bits_per_sample_obj) },
173-
{ MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audioio_wavefile_channel_count_obj) },
130+
AUDIOSAMPLE_FIELDS,
174131
};
175132
static MP_DEFINE_CONST_DICT(audioio_wavefile_locals_dict, audioio_wavefile_locals_dict_table);
176133

177134
static const audiosample_p_t audioio_wavefile_proto = {
178135
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
179-
.sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_wavefile_get_sample_rate,
180-
.bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_wavefile_get_bits_per_sample,
181-
.channel_count = (audiosample_channel_count_fun)common_hal_audioio_wavefile_get_channel_count,
182136
.reset_buffer = (audiosample_reset_buffer_fun)audioio_wavefile_reset_buffer,
183137
.get_buffer = (audiosample_get_buffer_fun)audioio_wavefile_get_buffer,
184-
.get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_wavefile_get_buffer_structure,
185138
};
186139

187140

shared-bindings/audiocore/__init__.c

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
#include <stdint.h>
88

99
#include "py/obj.h"
10+
#include "py/objproperty.h"
1011
#include "py/gc.h"
1112
#include "py/runtime.h"
1213

1314
#include "shared-bindings/audiocore/__init__.h"
1415
#include "shared-bindings/audiocore/RawSample.h"
1516
#include "shared-bindings/audiocore/WaveFile.h"
17+
#include "shared-bindings/util.h"
1618
// #include "shared-bindings/audiomixer/Mixer.h"
1719

1820
//| """Support for audio samples"""
@@ -24,15 +26,18 @@ static mp_obj_t audiocore_get_buffer(mp_obj_t sample_in) {
2426
uint32_t buffer_length = 0;
2527
audioio_get_buffer_result_t gbr = audiosample_get_buffer(sample_in, false, 0, &buffer, &buffer_length);
2628

29+
// audiosample_get_buffer checked that we're a sample so this is a safe cast
30+
audiosample_base_t *sample = MP_OBJ_TO_PTR(sample_in);
31+
2732
mp_obj_t result[2] = {mp_obj_new_int_from_uint(gbr), mp_const_none};
2833

2934
if (gbr != GET_BUFFER_ERROR) {
3035
bool single_buffer, samples_signed;
3136
uint32_t max_buffer_length;
3237
uint8_t spacing;
3338

34-
uint8_t bits_per_sample = audiosample_bits_per_sample(sample_in);
35-
audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
39+
uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample);
40+
audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
3641
// copies the data because the gc semantics of get_buffer are unclear
3742
void *result_buf = m_malloc(buffer_length);
3843
memcpy(result_buf, buffer, buffer_length);
@@ -55,7 +60,7 @@ static mp_obj_t audiocore_get_structure(mp_obj_t sample_in) {
5560
uint32_t max_buffer_length;
5661
uint8_t spacing;
5762

58-
audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
63+
audiosample_get_buffer_structure_checked(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
5964
mp_obj_t result[4] = {
6065
mp_obj_new_int_from_uint(single_buffer),
6166
mp_obj_new_int_from_uint(samples_signed),
@@ -92,4 +97,61 @@ const mp_obj_module_t audiocore_module = {
9297
.globals = (mp_obj_dict_t *)&audiocore_module_globals,
9398
};
9499

100+
bool audiosample_deinited(const audiosample_base_t *self) {
101+
return self->channel_count == 0;
102+
}
103+
104+
void audiosample_check_for_deinit(const audiosample_base_t *self) {
105+
if (audiosample_deinited(self)) {
106+
raise_deinited_error();
107+
}
108+
}
109+
110+
void audiosample_mark_deinit(audiosample_base_t *self) {
111+
self->channel_count = 0;
112+
}
113+
114+
// common implementation of channel_count property for audio samples
115+
static mp_obj_t audiosample_obj_get_channel_count(mp_obj_t self_in) {
116+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
117+
audiosample_check_for_deinit(self);
118+
return MP_OBJ_NEW_SMALL_INT(audiosample_get_channel_count(self));
119+
}
120+
MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_channel_count_obj, audiosample_obj_get_channel_count);
121+
122+
MP_PROPERTY_GETTER(audiosample_channel_count_obj,
123+
(mp_obj_t)&audiosample_get_channel_count_obj);
124+
125+
126+
// common implementation of bits_per_sample property for audio samples
127+
static mp_obj_t audiosample_obj_get_bits_per_sample(mp_obj_t self_in) {
128+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
129+
audiosample_check_for_deinit(self);
130+
return MP_OBJ_NEW_SMALL_INT(audiosample_get_bits_per_sample(self));
131+
}
132+
MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_bits_per_sample_obj, audiosample_obj_get_bits_per_sample);
133+
134+
MP_PROPERTY_GETTER(audiosample_bits_per_sample_obj,
135+
(mp_obj_t)&audiosample_get_bits_per_sample_obj);
136+
137+
// common implementation of sample_rate property for audio samples
138+
static mp_obj_t audiosample_obj_get_sample_rate(mp_obj_t self_in) {
139+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
140+
audiosample_check_for_deinit(self);
141+
return MP_OBJ_NEW_SMALL_INT(audiosample_get_sample_rate(audiosample_check(self_in)));
142+
}
143+
MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_sample_rate_obj, audiosample_obj_get_sample_rate);
144+
145+
static mp_obj_t audiosample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
146+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
147+
audiosample_check_for_deinit(self);
148+
audiosample_set_sample_rate(audiosample_check(self_in), mp_obj_get_int(sample_rate));
149+
return mp_const_none;
150+
}
151+
MP_DEFINE_CONST_FUN_OBJ_2(audiosample_set_sample_rate_obj, audiosample_obj_set_sample_rate);
152+
153+
MP_PROPERTY_GETSET(audiosample_sample_rate_obj,
154+
(mp_obj_t)&audiosample_get_sample_rate_obj,
155+
(mp_obj_t)&audiosample_set_sample_rate_obj);
156+
95157
MP_REGISTER_MODULE(MP_QSTR_audiocore, audiocore_module);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy