diff options
Diffstat (limited to 'apps/pcmbuf.c')
-rw-r--r-- | apps/pcmbuf.c | 319 |
1 files changed, 95 insertions, 224 deletions
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 7201d3981a..f2f94e3bc9 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -23,8 +23,9 @@ | |||
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "debug.h" | 24 | #include "debug.h" |
25 | #include <kernel.h> | 25 | #include <kernel.h> |
26 | #include "pcmbuf.h" | ||
27 | #include "pcm.h" | 26 | #include "pcm.h" |
27 | #include "pcm_mixer.h" | ||
28 | #include "pcmbuf.h" | ||
28 | #include "playback.h" | 29 | #include "playback.h" |
29 | #include "codec_thread.h" | 30 | #include "codec_thread.h" |
30 | 31 | ||
@@ -49,9 +50,6 @@ | |||
49 | #define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than | 50 | #define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than |
50 | this to the DMA */ | 51 | this to the DMA */ |
51 | #define CROSSFADE_BUFSIZE 8192 /* Size of the crossfade buffer */ | 52 | #define CROSSFADE_BUFSIZE 8192 /* Size of the crossfade buffer */ |
52 | #define AUX_BUFSIZE 512 /* Size of the aux buffer; can be 512 if no | ||
53 | resampling or timestretching is allowed in | ||
54 | the aux channel, must be 2048 otherwise */ | ||
55 | 53 | ||
56 | /* number of bytes played per second (sample rate * 2 channels * 2 bytes/sample) */ | 54 | /* number of bytes played per second (sample rate * 2 channels * 2 bytes/sample) */ |
57 | #define BYTERATE (NATIVE_FREQUENCY * 4) | 55 | #define BYTERATE (NATIVE_FREQUENCY * 4) |
@@ -91,6 +89,12 @@ static struct chunkdesc *first_desc; | |||
91 | /* Gapless playback */ | 89 | /* Gapless playback */ |
92 | static bool track_transition IDATA_ATTR; | 90 | static bool track_transition IDATA_ATTR; |
93 | 91 | ||
92 | /* Fade effect */ | ||
93 | static unsigned int fade_vol = MIX_AMP_UNITY; | ||
94 | |||
95 | /* Voice */ | ||
96 | static bool soft_mode = false; | ||
97 | |||
94 | #ifdef HAVE_CROSSFADE | 98 | #ifdef HAVE_CROSSFADE |
95 | /* Crossfade buffer */ | 99 | /* Crossfade buffer */ |
96 | static char *fadebuf IDATA_ATTR; | 100 | static char *fadebuf IDATA_ATTR; |
@@ -121,11 +125,6 @@ static size_t last_chunksize IDATA_ATTR; | |||
121 | static size_t pcmbuf_unplayed_bytes IDATA_ATTR; | 125 | static size_t pcmbuf_unplayed_bytes IDATA_ATTR; |
122 | static size_t pcmbuf_watermark IDATA_ATTR; | 126 | static size_t pcmbuf_watermark IDATA_ATTR; |
123 | 127 | ||
124 | /* Voice */ | ||
125 | static char *voicebuf IDATA_ATTR; | ||
126 | static struct chunkdesc *mix_chunk IDATA_ATTR; | ||
127 | static size_t pcmbuf_mix_sample IDATA_ATTR; | ||
128 | |||
129 | static bool low_latency_mode = false; | 128 | static bool low_latency_mode = false; |
130 | static bool flush_pcmbuf = false; | 129 | static bool flush_pcmbuf = false; |
131 | 130 | ||
@@ -317,10 +316,12 @@ static void boost_codec_thread(int pcm_fill_state) | |||
317 | * Also maintain buffer level above the watermark. */ | 316 | * Also maintain buffer level above the watermark. */ |
318 | static bool prepare_insert(size_t length) | 317 | static bool prepare_insert(size_t length) |
319 | { | 318 | { |
319 | bool playing = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED; | ||
320 | |||
320 | if (low_latency_mode) | 321 | if (low_latency_mode) |
321 | { | 322 | { |
322 | /* 1/4s latency. */ | 323 | /* 1/4s latency. */ |
323 | if (!LOW_DATA(1) && pcm_is_playing()) | 324 | if (!LOW_DATA(1) && playing) |
324 | return false; | 325 | return false; |
325 | } | 326 | } |
326 | 327 | ||
@@ -329,7 +330,7 @@ static bool prepare_insert(size_t length) | |||
329 | return false; | 330 | return false; |
330 | 331 | ||
331 | /* Maintain the buffer level above the watermark */ | 332 | /* Maintain the buffer level above the watermark */ |
332 | if (pcm_is_playing()) | 333 | if (playing) |
333 | { | 334 | { |
334 | /* Only codec thread initiates boost - voice boosts the cpu when playing | 335 | /* Only codec thread initiates boost - voice boosts the cpu when playing |
335 | a clip */ | 336 | a clip */ |
@@ -351,7 +352,7 @@ static bool prepare_insert(size_t length) | |||
351 | } | 352 | } |
352 | #endif | 353 | #endif |
353 | } | 354 | } |
354 | else /* pcm_is_playing */ | 355 | else /* !playing */ |
355 | { | 356 | { |
356 | /* Boost CPU for pre-buffer */ | 357 | /* Boost CPU for pre-buffer */ |
357 | trigger_cpu_boost(); | 358 | trigger_cpu_boost(); |
@@ -469,11 +470,14 @@ static size_t get_next_required_pcmbuf_size(void) | |||
469 | * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ | 470 | * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ |
470 | size_t pcmbuf_init(unsigned char *bufend) | 471 | size_t pcmbuf_init(unsigned char *bufend) |
471 | { | 472 | { |
473 | unsigned char *voicebuf; | ||
474 | |||
472 | pcmbuf_bufend = bufend; | 475 | pcmbuf_bufend = bufend; |
473 | pcmbuf_size = get_next_required_pcmbuf_size(); | 476 | pcmbuf_size = get_next_required_pcmbuf_size(); |
474 | write_chunk = (struct chunkdesc *)pcmbuf_bufend - | 477 | write_chunk = (struct chunkdesc *)pcmbuf_bufend - |
475 | NUM_CHUNK_DESCS(pcmbuf_size); | 478 | NUM_CHUNK_DESCS(pcmbuf_size); |
476 | voicebuf = (char *)write_chunk - AUX_BUFSIZE; | 479 | voicebuf = (unsigned char *)write_chunk - |
480 | voicebuf_init((unsigned char *)write_chunk); | ||
477 | #ifdef HAVE_CROSSFADE | 481 | #ifdef HAVE_CROSSFADE |
478 | fadebuf = voicebuf - CROSSFADE_BUFSIZE; | 482 | fadebuf = voicebuf - CROSSFADE_BUFSIZE; |
479 | pcmbuffer = fadebuf - pcmbuf_size; | 483 | pcmbuffer = fadebuf - pcmbuf_size; |
@@ -491,6 +495,8 @@ size_t pcmbuf_init(unsigned char *bufend) | |||
491 | 495 | ||
492 | pcmbuf_play_stop(); | 496 | pcmbuf_play_stop(); |
493 | 497 | ||
498 | pcmbuf_soft_mode(false); | ||
499 | |||
494 | return pcmbuf_bufend - pcmbuffer; | 500 | return pcmbuf_bufend - pcmbuffer; |
495 | } | 501 | } |
496 | 502 | ||
@@ -572,7 +578,7 @@ bool pcmbuf_start_track_change(bool auto_skip) | |||
572 | #ifdef HAVE_CROSSFADE | 578 | #ifdef HAVE_CROSSFADE |
573 | pcmbuf_is_crossfade_active() || | 579 | pcmbuf_is_crossfade_active() || |
574 | #endif | 580 | #endif |
575 | !pcm_is_playing()) | 581 | mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED) |
576 | { | 582 | { |
577 | pcmbuf_play_stop(); | 583 | pcmbuf_play_stop(); |
578 | pcm_play_unlock(); | 584 | pcm_play_unlock(); |
@@ -652,10 +658,6 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) | |||
652 | write_end_chunk->link = pcmbuf_current; | 658 | write_end_chunk->link = pcmbuf_current; |
653 | write_end_chunk = pcmbuf_current; | 659 | write_end_chunk = pcmbuf_current; |
654 | 660 | ||
655 | /* If we've read over the mix chunk while it's still mixing there */ | ||
656 | if (pcmbuf_current == mix_chunk) | ||
657 | mix_chunk = NULL; | ||
658 | |||
659 | #ifdef HAVE_CROSSFADE | 661 | #ifdef HAVE_CROSSFADE |
660 | /* If we've read over the crossfade chunk while it's still fading */ | 662 | /* If we've read over the crossfade chunk while it's still fading */ |
661 | if (pcmbuf_current == crossfade_chunk) | 663 | if (pcmbuf_current == crossfade_chunk) |
@@ -696,23 +698,23 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) | |||
696 | /* Force playback */ | 698 | /* Force playback */ |
697 | void pcmbuf_play_start(void) | 699 | void pcmbuf_play_start(void) |
698 | { | 700 | { |
699 | if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL) | 701 | if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED && |
702 | pcmbuf_unplayed_bytes && read_chunk != NULL) | ||
700 | { | 703 | { |
701 | logf("pcmbuf_play_start"); | 704 | logf("pcmbuf_play_start"); |
702 | last_chunksize = read_chunk->size; | 705 | last_chunksize = read_chunk->size; |
703 | pcmbuf_unplayed_bytes -= last_chunksize; | 706 | pcmbuf_unplayed_bytes -= last_chunksize; |
704 | pcm_play_data(pcmbuf_pcm_callback, | 707 | mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, |
705 | read_chunk->addr, last_chunksize); | 708 | pcmbuf_pcm_callback, NULL, 0); |
706 | } | 709 | } |
707 | } | 710 | } |
708 | 711 | ||
709 | void pcmbuf_play_stop(void) | 712 | void pcmbuf_play_stop(void) |
710 | { | 713 | { |
711 | logf("pcmbuf_play_stop"); | 714 | logf("pcmbuf_play_stop"); |
712 | pcm_play_stop(); | 715 | mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); |
713 | 716 | ||
714 | pcmbuf_unplayed_bytes = 0; | 717 | pcmbuf_unplayed_bytes = 0; |
715 | mix_chunk = NULL; | ||
716 | if (read_chunk) { | 718 | if (read_chunk) { |
717 | write_end_chunk->link = read_chunk; | 719 | write_end_chunk->link = read_chunk; |
718 | write_end_chunk = read_end_chunk; | 720 | write_end_chunk = read_end_chunk; |
@@ -737,8 +739,9 @@ void pcmbuf_play_stop(void) | |||
737 | void pcmbuf_pause(bool pause) | 739 | void pcmbuf_pause(bool pause) |
738 | { | 740 | { |
739 | logf("pcmbuf_pause: %s", pause?"pause":"play"); | 741 | logf("pcmbuf_pause: %s", pause?"pause":"play"); |
740 | if (pcm_is_playing()) | 742 | |
741 | pcm_play_pause(!pause); | 743 | if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED) |
744 | mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause); | ||
742 | else if (!pause) | 745 | else if (!pause) |
743 | pcmbuf_play_start(); | 746 | pcmbuf_play_start(); |
744 | } | 747 | } |
@@ -1031,102 +1034,6 @@ bool pcmbuf_is_same_size(void) | |||
1031 | #endif /* HAVE_CROSSFADE */ | 1034 | #endif /* HAVE_CROSSFADE */ |
1032 | 1035 | ||
1033 | 1036 | ||
1034 | /** Voice */ | ||
1035 | |||
1036 | /* Returns pcm buffer usage in percents (0 to 100). */ | ||
1037 | static int pcmbuf_usage(void) | ||
1038 | { | ||
1039 | return pcmbuf_unplayed_bytes * 100 / pcmbuf_size; | ||
1040 | } | ||
1041 | |||
1042 | static int pcmbuf_mix_free(void) | ||
1043 | { | ||
1044 | if (mix_chunk) | ||
1045 | { | ||
1046 | size_t my_mix_end = | ||
1047 | (size_t)&((int16_t *)mix_chunk->addr)[pcmbuf_mix_sample]; | ||
1048 | size_t my_write_pos = (size_t)&pcmbuffer[pcmbuffer_pos]; | ||
1049 | if (my_write_pos < my_mix_end) | ||
1050 | my_write_pos += pcmbuf_size; | ||
1051 | return (my_write_pos - my_mix_end) * 100 / pcmbuf_unplayed_bytes; | ||
1052 | } | ||
1053 | return 100; | ||
1054 | } | ||
1055 | |||
1056 | void *pcmbuf_request_voice_buffer(int *count) | ||
1057 | { | ||
1058 | /* A get-it-to-work-for-now hack (audio status could change by | ||
1059 | completion) */ | ||
1060 | if (audio_status() & AUDIO_STATUS_PLAY) | ||
1061 | { | ||
1062 | if (read_chunk == NULL) | ||
1063 | { | ||
1064 | return NULL; | ||
1065 | } | ||
1066 | else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 && | ||
1067 | (mix_chunk || read_chunk->link)) | ||
1068 | { | ||
1069 | *count = MIN(*count, AUX_BUFSIZE/4); | ||
1070 | return voicebuf; | ||
1071 | } | ||
1072 | else | ||
1073 | { | ||
1074 | return NULL; | ||
1075 | } | ||
1076 | } | ||
1077 | else | ||
1078 | { | ||
1079 | return pcmbuf_request_buffer(count); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | void pcmbuf_write_voice_complete(int count) | ||
1084 | { | ||
1085 | /* A get-it-to-work-for-now hack (audio status could have changed) */ | ||
1086 | if (!(audio_status() & AUDIO_STATUS_PLAY)) | ||
1087 | { | ||
1088 | pcmbuf_write_complete(count); | ||
1089 | return; | ||
1090 | } | ||
1091 | |||
1092 | int16_t *ibuf = (int16_t *)voicebuf; | ||
1093 | int16_t *obuf; | ||
1094 | size_t chunk_samples; | ||
1095 | |||
1096 | if (mix_chunk == NULL && read_chunk != NULL) | ||
1097 | { | ||
1098 | mix_chunk = read_chunk->link; | ||
1099 | /* Start 1/8s into the next chunk */ | ||
1100 | pcmbuf_mix_sample = BYTERATE / 16; | ||
1101 | } | ||
1102 | |||
1103 | if (!mix_chunk) | ||
1104 | return; | ||
1105 | |||
1106 | obuf = (int16_t *)mix_chunk->addr; | ||
1107 | chunk_samples = mix_chunk->size / sizeof (int16_t); | ||
1108 | |||
1109 | count <<= 1; | ||
1110 | |||
1111 | while (count-- > 0) | ||
1112 | { | ||
1113 | int32_t sample = *ibuf++; | ||
1114 | |||
1115 | if (pcmbuf_mix_sample >= chunk_samples) | ||
1116 | { | ||
1117 | mix_chunk = mix_chunk->link; | ||
1118 | if (!mix_chunk) | ||
1119 | return; | ||
1120 | pcmbuf_mix_sample = 0; | ||
1121 | obuf = (int16_t *)mix_chunk->addr; | ||
1122 | chunk_samples = mix_chunk->size / 2; | ||
1123 | } | ||
1124 | sample += obuf[pcmbuf_mix_sample] >> 2; | ||
1125 | obuf[pcmbuf_mix_sample++] = clip_sample_16(sample); | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | |||
1130 | /** Debug menu, other metrics */ | 1037 | /** Debug menu, other metrics */ |
1131 | 1038 | ||
1132 | /* Amount of bytes left in the buffer. */ | 1039 | /* Amount of bytes left in the buffer. */ |
@@ -1174,6 +1081,71 @@ unsigned char *pcmbuf_get_meminfo(size_t *length) | |||
1174 | #endif | 1081 | #endif |
1175 | 1082 | ||
1176 | 1083 | ||
1084 | /** Fading and channel volume control */ | ||
1085 | |||
1086 | /* Sync the channel amplitude to all states */ | ||
1087 | static void pcmbuf_update_volume(void) | ||
1088 | { | ||
1089 | unsigned int vol = fade_vol; | ||
1090 | |||
1091 | if (soft_mode) | ||
1092 | vol >>= 2; | ||
1093 | |||
1094 | mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol); | ||
1095 | } | ||
1096 | |||
1097 | /* Quiet-down the channel if 'shhh' is true or else play at normal level */ | ||
1098 | void pcmbuf_soft_mode(bool shhh) | ||
1099 | { | ||
1100 | soft_mode = shhh; | ||
1101 | pcmbuf_update_volume(); | ||
1102 | } | ||
1103 | |||
1104 | /* Fade channel in or out */ | ||
1105 | void pcmbuf_fade(bool fade, bool in) | ||
1106 | { | ||
1107 | if (!fade) | ||
1108 | { | ||
1109 | /* Simply set the level */ | ||
1110 | fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE; | ||
1111 | } | ||
1112 | else | ||
1113 | { | ||
1114 | /* Start from the opposing end */ | ||
1115 | fade_vol = in ? MIX_AMP_MUTE : MIX_AMP_UNITY; | ||
1116 | } | ||
1117 | |||
1118 | pcmbuf_update_volume(); | ||
1119 | |||
1120 | if (fade) | ||
1121 | { | ||
1122 | /* Do this on thread for now */ | ||
1123 | int old_prio = thread_set_priority(thread_self(), PRIORITY_REALTIME); | ||
1124 | |||
1125 | while (1) | ||
1126 | { | ||
1127 | /* Linear fade actually sounds better */ | ||
1128 | if (in) | ||
1129 | fade_vol += MIN(MIX_AMP_UNITY/16, MIX_AMP_UNITY - fade_vol); | ||
1130 | else | ||
1131 | fade_vol -= MIN(MIX_AMP_UNITY/16, fade_vol - MIX_AMP_MUTE); | ||
1132 | |||
1133 | pcmbuf_update_volume(); | ||
1134 | |||
1135 | if (fade_vol > MIX_AMP_MUTE && fade_vol < MIX_AMP_UNITY) | ||
1136 | { | ||
1137 | sleep(0); | ||
1138 | continue; | ||
1139 | } | ||
1140 | |||
1141 | break; | ||
1142 | } | ||
1143 | |||
1144 | thread_set_priority(thread_self(), old_prio); | ||
1145 | } | ||
1146 | } | ||
1147 | |||
1148 | |||
1177 | /** Misc */ | 1149 | /** Misc */ |
1178 | 1150 | ||
1179 | bool pcmbuf_is_lowdata(void) | 1151 | bool pcmbuf_is_lowdata(void) |
@@ -1201,107 +1173,6 @@ void pcmbuf_set_low_latency(bool state) | |||
1201 | 1173 | ||
1202 | unsigned long pcmbuf_get_latency(void) | 1174 | unsigned long pcmbuf_get_latency(void) |
1203 | { | 1175 | { |
1204 | return (pcmbuf_unplayed_bytes + pcm_get_bytes_waiting()) * 1000 / BYTERATE; | 1176 | return (pcmbuf_unplayed_bytes + |
1205 | } | 1177 | mixer_channel_get_bytes_waiting(PCM_MIXER_CHAN_PLAYBACK)) * 1000 / BYTERATE; |
1206 | |||
1207 | #ifndef HAVE_HARDWARE_BEEP | ||
1208 | #define MINIBUF_SAMPLES (NATIVE_FREQUENCY / 1000 * KEYCLICK_DURATION) | ||
1209 | #define MINIBUF_SIZE (MINIBUF_SAMPLES*4) | ||
1210 | |||
1211 | /* Generates a constant square wave sound with a given frequency | ||
1212 | in Hertz for a duration in milliseconds. */ | ||
1213 | void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude) | ||
1214 | { | ||
1215 | unsigned int step = 0xffffffffu / NATIVE_FREQUENCY * frequency; | ||
1216 | int32_t phase = 0; | ||
1217 | int16_t *bufptr, *bufstart, *bufend; | ||
1218 | int32_t sample; | ||
1219 | int nsamples = NATIVE_FREQUENCY / 1000 * duration; | ||
1220 | bool mix = read_chunk != NULL && read_chunk->link != NULL; | ||
1221 | int i; | ||
1222 | |||
1223 | bufend = SKIPBYTES((int16_t *)pcmbuffer, pcmbuf_size); | ||
1224 | |||
1225 | /* Find the insertion point and set bufstart to the start of it */ | ||
1226 | if (mix) | ||
1227 | { | ||
1228 | /* Get the currently playing chunk at the current position. */ | ||
1229 | bufstart = (int16_t *)pcm_play_dma_get_peak_buffer(&i); | ||
1230 | |||
1231 | /* If above isn't implemented or pcm is stopped, no beepeth. */ | ||
1232 | if (!bufstart || !pcm_is_playing()) | ||
1233 | return; | ||
1234 | |||
1235 | /* Give 5ms clearance. */ | ||
1236 | bufstart += BYTERATE / 200; | ||
1237 | |||
1238 | #ifdef HAVE_PCM_DMA_ADDRESS | ||
1239 | /* Returned peak addresses are DMA addresses */ | ||
1240 | bufend = pcm_dma_addr(bufend); | ||
1241 | #endif | ||
1242 | |||
1243 | /* Wrapped above? */ | ||
1244 | if (bufstart >= bufend) | ||
1245 | bufstart -= pcmbuf_size; | ||
1246 | |||
1247 | /* NOTE: On some targets using hardware DMA, cache range flushing may | ||
1248 | * be required or the writes may not be picked up by the controller. | ||
1249 | * An incremental flush should be done periodically during the mixdown. */ | ||
1250 | } | ||
1251 | else if (nsamples <= MINIBUF_SAMPLES) | ||
1252 | { | ||
1253 | static int16_t minibuf[MINIBUF_SAMPLES*2] __attribute__((aligned(4))); | ||
1254 | /* Use mini buffer */ | ||
1255 | bufstart = minibuf; | ||
1256 | bufend = SKIPBYTES(bufstart, MINIBUF_SIZE); | ||
1257 | } | ||
1258 | else if (!audio_buffer_state_trashed()) | ||
1259 | { | ||
1260 | /* Use pcmbuffer */ | ||
1261 | bufstart = (int16_t *)pcmbuffer; | ||
1262 | } | ||
1263 | else | ||
1264 | { | ||
1265 | /* No place */ | ||
1266 | return; | ||
1267 | } | ||
1268 | |||
1269 | bufptr = bufstart; | ||
1270 | |||
1271 | /* Mix square wave into buffer */ | ||
1272 | for (i = 0; i < nsamples; ++i) | ||
1273 | { | ||
1274 | int32_t amp = (phase >> 31) ^ (int32_t)amplitude; | ||
1275 | sample = mix ? *bufptr : 0; | ||
1276 | *bufptr++ = clip_sample_16(sample + amp); | ||
1277 | if (bufptr >= bufend) | ||
1278 | bufptr = (int16_t *)pcmbuffer; | ||
1279 | sample = mix ? *bufptr : 0; | ||
1280 | *bufptr++ = clip_sample_16(sample + amp); | ||
1281 | if (bufptr >= bufend) | ||
1282 | bufptr = (int16_t *)pcmbuffer; | ||
1283 | |||
1284 | phase += step; | ||
1285 | } | ||
1286 | |||
1287 | pcm_play_lock(); | ||
1288 | #ifdef HAVE_RECORDING | ||
1289 | pcm_rec_lock(); | ||
1290 | #endif | ||
1291 | |||
1292 | /* Kick off playback if required and it won't interfere */ | ||
1293 | if (!pcm_is_playing() | ||
1294 | #ifdef HAVE_RECORDING | ||
1295 | && !pcm_is_recording() | ||
1296 | #endif | ||
1297 | ) | ||
1298 | { | ||
1299 | pcm_play_data(NULL, (unsigned char *)bufstart, nsamples * 4); | ||
1300 | } | ||
1301 | |||
1302 | pcm_play_unlock(); | ||
1303 | #ifdef HAVE_RECORDING | ||
1304 | pcm_rec_unlock(); | ||
1305 | #endif | ||
1306 | } | 1178 | } |
1307 | #endif /* HAVE_HARDWARE_BEEP */ | ||