void start_sound() { while(read_sound_int(&SOUNDSTATUS->mode) != MODE_PLAY) { memset4((void*)RING_BUF, 0, SAMPLES_TO_BYTES(RING_BUFFER_SAMPLES+1)); memset4((void*)RING_BUF+STEREO_OFFSET, 0, SAMPLES_TO_BYTES(RING_BUFFER_SAMPLES+1)); do_sound_command(CMD_SET_MODE(MODE_PLAY)); } }
void SSRunMixer(void) { int bytes_copied; int bytestogo; int c; int i; int pos = read_sound_int(&SOUNDSTATUS->samplepos); memset(tmp_sound_buffer, 0, sizeof(tmp_sound_buffer)); const int len = 2*SAMPLES_TO_BYTES(AUDIO_SIZE); // get data for all channels and add it to the mix for(c=0;c<SS_NUM_CHANNELS;c++) { if (channel[c].head==channel[c].tail) continue; bytestogo = len; mix_pos = 0; while(bytestogo > 0) { bytes_copied = AddBuffer(&channel[c], bytestogo); bytestogo -= bytes_copied; if (channel[c].head==channel[c].tail) { // ran out of chunks before buffer full // clear remaining portion of mixbuffer if (bytestogo) { memset(&mixbuffer[mix_pos], 0, bytestogo); } break; } } MixAudio(tmp_sound_buffer, mixbuffer, len, channel[c].volume); } // tell any callbacks that had a chunk finish, that their chunk finished for(c=0;c<SS_NUM_CHANNELS;c++) { if (channel[c].FinishedCB) { for(i=0;i<channel[c].nFinishedChunks;i++) { //stat("Telling channel %d's handler that chunk %d finished", c, channel[c].FinishedChunkUserdata[i]); (*channel[c].FinishedCB)(c, channel[c].FinishedChunkUserdata[i]); } } channel[c].nFinishedChunks = 0; } memcpy4s(RING_BUF + pos, tmp_sound_buffer, SAMPLES_TO_BYTES(AUDIO_SIZE)); }
static int siren14seek(struct ast_filestream *fs, off_t sample_offset, int whence) { off_t offset = 0, min = 0, cur, max; sample_offset = SAMPLES_TO_BYTES(sample_offset); cur = ftello(fs->f); fseeko(fs->f, 0, SEEK_END); max = ftello(fs->f); if (whence == SEEK_SET) offset = sample_offset; else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) offset = sample_offset + cur; else if (whence == SEEK_END) offset = max - sample_offset; if (whence != SEEK_FORCECUR) offset = (offset > max) ? max : offset; /* always protect against seeking past begining. */ offset = (offset < min) ? min : offset; return fseeko(fs->f, offset, SEEK_SET); }
/* Called to copy samples to the decode fifo when we are doing * a transition - crossfade or fade in. This method applies gain * to both the new signal and the one that's already in the fifo. */ static void decode_transition_copy_bytes(sample_t *buffer, size_t nbytes) { sample_t sample, *sptr; int nsamples, s; size_t bytes_read; fft_fixed in_gain, out_gain; ASSERT_AUDIO_LOCKED(); while (nbytes) { bytes_read = SAMPLES_TO_BYTES(transition_sample_step - transition_samples_in_step); if (bytes_read > nbytes) { bytes_read = nbytes; } nsamples = BYTES_TO_SAMPLES(bytes_read); sptr = (sample_t *)(void *)(decode_fifo_buf + decode_audio->fifo.wptr); in_gain = transition_gain; out_gain = FIXED_ONE - in_gain; if (crossfade_started) { for (s=0; s<nsamples * 2; s++) { sample = fixed_mul(out_gain, *sptr); sample += fixed_mul(in_gain, *buffer++); *sptr++ = sample; } } else { for (s=0; s<nsamples * 2; s++) { *sptr++ = fixed_mul(in_gain, *buffer++); } } fifo_wptr_incby(&decode_audio->fifo, bytes_read); nbytes -= bytes_read; transition_samples_in_step += nsamples; while (transition_samples_in_step >= transition_sample_step) { transition_samples_in_step -= transition_sample_step; transition_gain += transition_gain_step; } } }
void *memcpy4s(void *s1, const void *s2, unsigned int n) { unsigned int *p1a = s1; unsigned int *p1b = (void*)(((char *)s1)+SAMPLES_TO_BYTES(STEREO_OFFSET)); const unsigned int *p2 = s2; n+=3; n>>=2; while(n--) { #if SAMPLE_MODE == 0 unsigned int a = *p2++; unsigned int b = *p2++; *p1a++ = (a & 0xffff) | ((b & 0xffff)<<16); *p1b++ = ((a & 0xffff0000)>>16) | (b & 0xffff0000); #else #error 8 bit stereo not implemented... #endif } return s1; }
static bool_t upload_samples(sample_t *buffer, u32_t nsamples) { ssize_t n, len; if (!upload_fd) { return FALSE; } len = SAMPLES_TO_BYTES(nsamples); while (len) { n = send(upload_fd, buffer, len, 0); if (n < 0) { LOG_WARN(log_audio_decode, "send failed (%s)", strerror(errno)); upload_close(); break; } len -= n; } return TRUE; }
static int g719seek(struct ast_filestream *fs, off_t sample_offset, int whence) { off_t offset = 0, min = 0, cur, max; sample_offset = SAMPLES_TO_BYTES(sample_offset); if ((cur = ftello(fs->f)) < 0) { ast_log(AST_LOG_WARNING, "Unable to determine current position in g719 filestream %p: %s\n", fs, strerror(errno)); return -1; } if (fseeko(fs->f, 0, SEEK_END) < 0) { ast_log(AST_LOG_WARNING, "Unable to seek to end of g719 filestream %p: %s\n", fs, strerror(errno)); return -1; } if ((max = ftello(fs->f)) < 0) { ast_log(AST_LOG_WARNING, "Unable to determine max position in g719 filestream %p: %s\n", fs, strerror(errno)); return -1; } if (whence == SEEK_SET) offset = sample_offset; else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) offset = sample_offset + cur; else if (whence == SEEK_END) offset = max - sample_offset; if (whence != SEEK_FORCECUR) offset = (offset > max) ? max : offset; /* always protect against seeking past begining. */ offset = (offset < min) ? min : offset; return fseeko(fs->f, offset, SEEK_SET); }
void decode_output_samples(sample_t *buffer, u32_t nsamples, int sample_rate) { size_t bytes_out; /* Some decoders can pass no samples at the start of the track. Stop * early, otherwise we may send the track start event at the wrong * time. */ if (nsamples == 0) { return; } // XXXX full port from ip3k decode_audio_lock(); if (decode_first_buffer) { LOG_DEBUG(log_audio_decode, "first buffer sample_rate=%d", sample_rate); upload_open(); crossfade_started = FALSE; decode_audio->track_start_point = decode_audio->fifo.wptr; if (decode_transition_type & TRANSITION_CROSSFADE) { size_t crossfadeBytes; fft_fixed interval; if (decode_transition_type & TRANSITION_IMMEDIATE) { size_t wanted = SAMPLES_TO_BYTES(decode_transition_period * decode_audio->track_sample_rate); size_t used = fifo_bytes_used(&decode_audio->fifo); if (used > wanted) { size_t skip = used - wanted; if (skip > decode_audio->fifo.wptr) decode_audio->fifo.wptr += decode_audio->fifo.size; decode_audio->fifo.wptr -= skip; } } /* We are being asked to do a crossfade. Find out * if it is possible. */ interval = determine_transition_interval(sample_rate, decode_transition_period, &crossfadeBytes); if (interval) { LOG_DEBUG(log_audio_decode, "Starting CROSSFADE over %d seconds, requiring %d bytes", fixed_to_s32(interval), (unsigned int)crossfadeBytes); /* Buffer position to stop crossfade */ crossfade_ptr = decode_audio->fifo.wptr; /* Buffer position to start crossfade */ if (crossfadeBytes > decode_audio->fifo.wptr) decode_audio->fifo.wptr += decode_audio->fifo.size; decode_audio->fifo.wptr -= crossfadeBytes; /* Gain steps */ transition_gain_step = fixed_div(FIXED_ONE, fixed_mul(interval, s32_to_fixed(TRANSITION_STEPS_PER_SECOND))); transition_gain = 0; transition_sample_step = sample_rate / TRANSITION_STEPS_PER_SECOND; transition_samples_in_step = 0; crossfade_started = TRUE; decode_audio->track_start_point = decode_audio->fifo.wptr; } /* * else there aren't enough leftover samples from the * previous track, so abort the transition. */ } else if (decode_transition_type & TRANSITION_FADE_IN) { /* The transition is a fade in. */ LOG_DEBUG(log_audio_decode, "Starting FADE_IN over %d seconds", decode_transition_period); /* Gain steps */ transition_gain_step = fixed_div(FIXED_ONE, s32_to_fixed(decode_transition_period * TRANSITION_STEPS_PER_SECOND)); transition_gain = 0; transition_sample_step = sample_rate / TRANSITION_STEPS_PER_SECOND; transition_samples_in_step = 0; } decode_audio->track_copyright = streambuf_is_copyright(); decode_audio->track_sample_rate = sample_rate; decode_audio->check_start_point = TRUE; decode_first_buffer = FALSE; } if (upload_samples(buffer, nsamples)) { decode_audio_unlock(); return; } /* If output_channels is set, copy left samples to right, or vice versa */ if (output_channels) { unsigned int i; if (output_channels & OUTPUT_CHANNEL_LEFT) { for (i = 0; i < nsamples * 2; i += 2) { buffer[i+1] = buffer[i]; } } else { for (i = 0; i < nsamples * 2; i += 2) { buffer[i] = buffer[i+1]; } } } decode_apply_track_gain(buffer, nsamples); bytes_out = SAMPLES_TO_BYTES(nsamples); while (bytes_out) { size_t wrap, bytes_write, bytes_remaining; /* The size of the output write is limied by the * space untill our fifo wraps. */ wrap = fifo_bytes_until_wptr_wrap(&decode_audio->fifo); /* When crossfading limit the output write to the * end of the transition. */ if (crossfade_started) { bytes_remaining = decode_transition_bytes_remaining(crossfade_ptr); if (bytes_remaining < wrap) { wrap = bytes_remaining; } } bytes_write = bytes_out; if (bytes_write > wrap) { bytes_write = wrap; } if (transition_gain_step) { decode_transition_copy_bytes(buffer, bytes_write); if ((crossfade_started && decode_audio->fifo.wptr == crossfade_ptr) || transition_gain >= FIXED_ONE) { LOG_DEBUG(log_audio_decode, "Completed transition"); transition_gain_step = 0; crossfade_started = FALSE; } } else { memcpy(decode_fifo_buf + decode_audio->fifo.wptr, buffer, bytes_write); fifo_wptr_incby(&decode_audio->fifo, bytes_write); } buffer += (bytes_write / sizeof(sample_t)); bytes_out -= bytes_write; } decode_audio_unlock(); }