void Voice::Interpolate(sample_t* pSrc) { float effective_volume = 1; // TODO: use the art. data instead int i = 0; // ************************************************ // TODO: ARTICULATION DATA HANDLING IS MISSING HERE // ************************************************ // FIXME: assuming either mono or stereo if (this->pSample->Channels == 2) { // Stereo Sample while (i < this->OutputBufferSize) { #ifdef USE_LINEAR_INTERPOLATION int pos_int = double_to_int(this->Pos); // integer position float pos_fract = this->Pos - pos_int; // fractional part of position pos_int <<= 1; // left channel this->pOutput[i++] += effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int])); // right channel this->pOutput[i++] += effective_volume * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1])); #else // polynomial interpolation //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile xm1 = pSrc[pos_int]; x0 = pSrc[pos_int+1]; x1 = pSrc[pos_int+2]; x2 = pSrc[pos_int+3]; a = (3 * (x0-x1) - xm1 + x2) / 2; b = 2 * x1 + xm1 - (5 * x0 + x2) / 2; c = (x1 - xm1) / 2; this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0); #endif // USE_LINEAR_INTERPOLATION this->Pos += this->CurrentPitch; } } else { // Mono Sample while (i < this->OutputBufferSize) { #ifdef USE_LINEAR_INTERPOLATION int pos_int = double_to_int(this->Pos); // integer position float pos_fract = this->Pos - pos_int; // fractional part of position float sample_point = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int])); this->pOutput[i] += sample_point; this->pOutput[i+1] += sample_point; i += 2; #else // polynomial interpolation //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile xm1 = pSrc[pos_int]; x0 = pSrc[pos_int+1]; x1 = pSrc[pos_int+2]; x2 = pSrc[pos_int+3]; a = (3 * (x0-x1) - xm1 + x2) / 2; b = 2 * x1 + xm1 - (5 * x0 + x2) / 2; c = (x1 - xm1) / 2; this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0); #endif this->Pos += this->CurrentPitch; } } }
void Voice::RenderAudio() { switch (this->PlaybackState) { case playback_state_ram: { Interpolate((sample_t*) pSample->GetCache().pStart); if (DiskVoice) { // check if we reached the allowed limit of the sample RAM cache if (Pos > MaxRAMPos) { dmsg(("Voice: switching to disk playback (Pos=%f)\n", Pos)); this->PlaybackState = playback_state_disk; } } else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) { this->PlaybackState = playback_state_end; } } break; case playback_state_disk: { if (!DiskStreamRef.pStream) { // check if the disk thread created our ordered disk stream in the meantime DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID); if (!DiskStreamRef.pStream) { std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush; pDiskThread->OrderDeletionOfStream(&DiskStreamRef); this->Active = false; return; } DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos)); Pos -= double_to_int(Pos); } // add silence sample at the end if we reached the end of the stream (for the interpolator) if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (OutputBufferSize << MAX_PITCH) / pSample->Channels) { DiskStreamRef.pStream->WriteSilence((OutputBufferSize << MAX_PITCH) / pSample->Channels); this->PlaybackState = playback_state_end; } sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from Interpolate(ptr); DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels); Pos -= double_to_int(Pos); } break; case playback_state_end: this->Active = false; // free voice break; } }
int __fixdfsi(double a) { double_t da; da.val = a; return double_to_int(da.data); }
NODE * format_val(char *format, int index, register NODE *s) { char buf[BUFSIZ]; register char *sp = buf; double val; char *orig, *trans, save; if (! do_traditional && (s->flags & INTLSTR) != 0) { save = s->stptr[s->stlen]; s->stptr[s->stlen] = '\0'; orig = s->stptr; trans = dgettext(TEXTDOMAIN, orig); s->stptr[s->stlen] = save; return tmp_string(trans, strlen(trans)); } /* not an integral value, or out of range */ if ((val = double_to_int(s->numbr)) != s->numbr || val < LONG_MIN || val > LONG_MAX) { /* * Once upon a time, if GFMT_WORKAROUND wasn't defined, * we just blindly did this: * sprintf(sp, format, s->numbr); * s->stlen = strlen(sp); * s->stfmt = (char) index; * but that's no good if, e.g., OFMT is %s. So we punt, * and just always format the value ourselves. */ NODE *dummy, *r; unsigned short oflags; extern NODE **fmt_list; /* declared in eval.c */ /* create dummy node for a sole use of format_tree */ getnode(dummy); dummy->type = Node_expression_list; dummy->lnode = s; dummy->rnode = NULL; oflags = s->flags; s->flags |= PERM; /* prevent from freeing by format_tree() */ r = format_tree(format, fmt_list[index]->stlen, dummy, 2); s->flags = oflags; s->stfmt = (char) index; s->stlen = r->stlen; s->stptr = r->stptr; freenode(r); /* Do not free_temp(r)! We want */ freenode(dummy); /* to keep s->stptr == r->stpr. */ goto no_malloc; } else { /* integral value */ /* force conversion to long only once */ register long num = (long) val; if (num < NVAL && num >= 0) { sp = (char *) values[num]; s->stlen = 1; } else { (void) sprintf(sp, "%ld", num); s->stlen = strlen(sp); } s->stfmt = -1; } emalloc(s->stptr, char *, s->stlen + 2, "format_val"); memcpy(s->stptr, sp, s->stlen+1); no_malloc: s->stref = 1; s->flags |= STR; s->flags &= ~UNINITIALIZED; return s; }