private static string PrintForceMode(OpusMode mode) { if (mode == OpusMode.MODE_CELT_ONLY) { return("CELT"); } if (mode == OpusMode.MODE_SILK_ONLY) { return("SILK"); } return(" "); }
/// <summary> /// OPUS_DECODER_RESET_START /// </summary> internal void PartialReset() { stream_channels = 0; bandwidth = 0; mode = 0; prev_mode = 0; frame_size = 0; prev_redundancy = 0; last_packet_duration = 0; rangeFinal = 0; // fixme: do these get reset here? I don't think they do because init_celt and init_silk should both call RESET_STATE on their respective states //SilkDecoder.Reset(); //CeltDecoder.Reset(); }
/** Initializes a previously allocated decoder state. * The state must be at least the size returned by opus_decoder_get_size(). * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. * @param [in] st <tt>OpusDecoder*</tt>: Decoder state. * @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz). * This must be one of 8000, 12000, 16000, * 24000, or 48000. * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode * @retval #OPUS_OK Success or @ref opus_errorcodes */ internal int opus_decoder_init(int Fs, int channels) { SilkDecoder silk_dec; CeltDecoder celt_dec; int ret; if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) || (channels != 1 && channels != 2)) { return(OpusError.OPUS_BAD_ARG); } this.Reset(); /* Initialize SILK encoder */ silk_dec = this.SilkDecoder; celt_dec = this.Celt_Decoder; this.stream_channels = this.channels = channels; this.Fs = Fs; this.DecControl.API_sampleRate = this.Fs; this.DecControl.nChannelsAPI = this.channels; /* Reset decoder */ ret = DecodeAPI.silk_InitDecoder(silk_dec); if (ret != 0) { return(OpusError.OPUS_INTERNAL_ERROR); } /* Initialize CELT decoder */ ret = celt_dec.celt_decoder_init(Fs, channels); if (ret != OpusError.OPUS_OK) { return(OpusError.OPUS_INTERNAL_ERROR); } celt_dec.SetSignalling(0); this.prev_mode = 0; this.frame_size = Fs / 400; return(OpusError.OPUS_OK); }
internal static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels) { int period; byte toc; period = 0; while (framerate < 400) { framerate <<= 1; period++; } if (mode == OpusMode.MODE_SILK_ONLY) { toc = (byte)((bandwidth - OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) << 5); toc |= (byte)((period - 2) << 3); } else if (mode == OpusMode.MODE_CELT_ONLY) { int tmp = bandwidth - OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; if (tmp < 0) { tmp = 0; } toc = 0x80; toc |= (byte)(tmp << 5); toc |= (byte)(period << 3); } else /* Hybrid */ { toc = 0x60; toc |= (byte)((bandwidth - OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) << 4); toc |= (byte)((period - 2) << 3); } toc |= (byte)((channels == 2 ? 1 : 0) << 2); return(toc); }
public static void Main(string[] args) { LoadTestFile(8, false); LoadTestFile(12, false); LoadTestFile(16, false); LoadTestFile(24, false); LoadTestFile(48, false); LoadTestFile(8, true); LoadTestFile(12, true); LoadTestFile(16, true); LoadTestFile(24, true); LoadTestFile(48, true); OpusApplication[] Applications = new OpusApplication[] { OpusApplication.OPUS_APPLICATION_AUDIO, OpusApplication.OPUS_APPLICATION_VOIP, OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY }; int[] Bitrates = new int[] { -1, 6, 16, 20, 32, 64, 500 }; int[] Channels = new int[] { 1, 2 }; int[] Complexities = new int[] { 0, 2, 4, 6, 8, 10 }; int[] SampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; double[] FrameSizes = new double[] { 2.5, 5, 10, 20, 40, 60 }; int[] PacketLosses = new int[] { 0, 20 }; OpusMode[] ForceModes = new OpusMode[] { OpusMode.MODE_AUTO, OpusMode.MODE_CELT_ONLY, OpusMode.MODE_SILK_ONLY }; bool[] DTXModes = new bool[] { false, true }; int[] VBRModes = new int[] { 0, 1, 2 }; IList <TestParameters> allTests = new List <TestParameters>(); for (int app_idx = 0; app_idx < Applications.Length; app_idx++) { for (int plc_idx = 0; plc_idx < PacketLosses.Length; plc_idx++) { for (int chan_idx = 0; chan_idx < Channels.Length; chan_idx++) { for (int sr_idx = 0; sr_idx < SampleRates.Length; sr_idx++) { for (int fs_idx = 0; fs_idx < FrameSizes.Length; fs_idx++) { for (int cpx_idx = 0; cpx_idx < Complexities.Length; cpx_idx++) { for (int bit_idx = 0; bit_idx < Bitrates.Length; bit_idx++) { for (int fm_idx = 0; fm_idx < ForceModes.Length; fm_idx++) { for (int dtx_idx = 0; dtx_idx < DTXModes.Length; dtx_idx++) { for (int vbr_idx = 0; vbr_idx < VBRModes.Length; vbr_idx++) { TestParameters newParams = new TestParameters() { Application = Applications[app_idx], Bitrate = Bitrates[bit_idx], Channels = Channels[chan_idx], Complexity = Complexities[cpx_idx], PacketLossPercent = PacketLosses[plc_idx], SampleRate = SampleRates[sr_idx], FrameSize = FrameSizes[fs_idx], ForceMode = ForceModes[fm_idx], UseDTX = DTXModes[dtx_idx] }; if (VBRModes[vbr_idx] == 0) { newParams.UseVBR = false; newParams.ConstrainedVBR = false; } else if (VBRModes[vbr_idx] == 1) { newParams.UseVBR = true; newParams.ConstrainedVBR = false; } else if (VBRModes[vbr_idx] == 2) { newParams.UseVBR = true; newParams.ConstrainedVBR = true; } // Validate params if (newParams.Bitrate > 40 || newParams.FrameSize < 10) { // No FEC outside of SILK mode if (newParams.PacketLossPercent > 0) { continue; } // No DTX outside of SILK mode if (newParams.UseDTX) { continue; } if (newParams.ForceMode == OpusMode.MODE_SILK_ONLY) { continue; } } // Constrained VBR only applies to CELT if (newParams.ForceMode == OpusMode.MODE_SILK_ONLY && newParams.ConstrainedVBR) { continue; } // 12Khz + 2.5ms triggers an opus bug for now if (newParams.SampleRate == 12000 && newParams.FrameSize < 5) { continue; } allTests.Add(newParams); } } } } } } } } } } TestParameters[] allTestsRandom = allTests.ToArray(); int numTestCases = allTests.Count; Console.WriteLine("Preparing " + numTestCases + " test cases"); // Shuffle the test list if (true) { TestParameters temp; int a; int b; Random rand = new Random(); for (int c = 0; c < numTestCases; c++) { a = rand.Next(numTestCases); b = rand.Next(numTestCases); temp = allTestsRandom[a]; allTestsRandom[a] = allTestsRandom[b]; allTestsRandom[b] = temp; } } double concentusTime = 0.001; double opusTime = 0; int passedTests = 0; int testsRun = 0; foreach (TestParameters p in allTestsRandom) { testsRun++; Console.Write("{0,5} {1} {2} Cpx={3,2} {4}Kbps {5,2}Khz {6,3} Ms PLC {7,2}% {8} {9} {10}... ", testsRun, PrintApplication(p.Application), p.Channels == 1 ? "Mono " : "Stereo", p.Complexity, p.Bitrate > 0 ? string.Format("{0,3}", p.Bitrate) : "VAR", p.SampleRate / 1000, p.FrameSize, p.PacketLossPercent, PrintVBRMode(p), p.UseDTX ? "DTX" : " ", PrintForceMode(p.ForceMode)); TestResults response = TestDriver.RunTest(p, GetTestSample(p)); if (response.Passed) { passedTests++; if (passedTests > 7) { concentusTime *= 0.999; opusTime *= 0.999; concentusTime += response.ConcentusTimeMs; opusTime += response.OpusTimeMs; } Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("{0} (Speed {1:F2}% Pass {2:F2}%)", response.Message, (opusTime * 100 / concentusTime), ((double)passedTests * 100 / testsRun)); Console.ForegroundColor = ConsoleColor.Gray; } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("FAIL: " + response.Message); Console.ForegroundColor = ConsoleColor.Gray; //if (response.FrameCount == 0) //{ // PrintShortArray(response.FailureFrame); // Console.WriteLine(response.FrameLength); // Console.ReadLine(); //} } } Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("All tests FINISHED"); Console.WriteLine("{0} out of {1} tests passed ({2:F2}%)", passedTests, numTestCases, ((double)passedTests * 100 / numTestCases)); Console.WriteLine("Speed benchmark was {0:F2}%", (opusTime * 100 / concentusTime)); }
internal int opus_decode_native(byte[] data, int data_ptr, int len, short[] pcm_out, int pcm_out_ptr, int frame_size, int decode_fec, int self_delimited, out int packet_offset, int soft_clip) { int i, nb_samples; int count, offset; byte toc; int packet_frame_size, packet_stream_channels; packet_offset = 0; OpusBandwidth packet_bandwidth; OpusMode packet_mode; /* 48 x 2.5 ms = 120 ms */ // fixme: make sure these values can fit in an int16 short[] size = new short[48]; if (decode_fec < 0 || decode_fec > 1) { return(OpusError.OPUS_BAD_ARG); } /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ if ((decode_fec != 0 || len == 0 || data == null) && frame_size % (this.Fs / 400) != 0) { return(OpusError.OPUS_BAD_ARG); } if (len == 0 || data == null) { int pcm_count = 0; do { int ret; ret = opus_decode_frame(null, 0, 0, pcm_out, pcm_out_ptr + (pcm_count * this.channels), frame_size - pcm_count, 0); if (ret < 0) { return(ret); } pcm_count += ret; } while (pcm_count < frame_size); Inlines.OpusAssert(pcm_count == frame_size); this.last_packet_duration = pcm_count; return(pcm_count); } else if (len < 0) { return(OpusError.OPUS_BAD_ARG); } packet_mode = OpusPacketInfo.GetEncoderMode(data, data_ptr); packet_bandwidth = OpusPacketInfo.GetBandwidth(data, data_ptr); packet_frame_size = OpusPacketInfo.GetNumSamplesPerFrame(data, data_ptr, this.Fs); packet_stream_channels = OpusPacketInfo.GetNumEncodedChannels(data, data_ptr); count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out toc, null, null, 0, size, 0, out offset, out packet_offset); if (count < 0) { return(count); } data_ptr += offset; if (decode_fec != 0) { int dummy; int duration_copy; int ret; /* If no FEC can be present, run the PLC (recursive call) */ if (frame_size < packet_frame_size || packet_mode == OpusMode.MODE_CELT_ONLY || this.mode == OpusMode.MODE_CELT_ONLY) { return(opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size, 0, 0, out dummy, soft_clip)); } /* Otherwise, run the PLC on everything except the size for which we might have FEC */ duration_copy = this.last_packet_duration; if (frame_size - packet_frame_size != 0) { ret = opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size - packet_frame_size, 0, 0, out dummy, soft_clip); if (ret < 0) { this.last_packet_duration = duration_copy; return(ret); } Inlines.OpusAssert(ret == frame_size - packet_frame_size); } /* Complete with FEC */ this.mode = packet_mode; this.bandwidth = packet_bandwidth; this.frame_size = packet_frame_size; this.stream_channels = packet_stream_channels; ret = opus_decode_frame(data, data_ptr, size[0], pcm_out, pcm_out_ptr + (this.channels * (frame_size - packet_frame_size)), packet_frame_size, 1); if (ret < 0) { return(ret); } else { this.last_packet_duration = frame_size; return(frame_size); } } if (count * packet_frame_size > frame_size) { return(OpusError.OPUS_BUFFER_TOO_SMALL); } /* Update the state as the last step to avoid updating it on an invalid packet */ this.mode = packet_mode; this.bandwidth = packet_bandwidth; this.frame_size = packet_frame_size; this.stream_channels = packet_stream_channels; nb_samples = 0; for (i = 0; i < count; i++) { int ret; ret = opus_decode_frame(data, data_ptr, size[i], pcm_out, pcm_out_ptr + (nb_samples * this.channels), frame_size - nb_samples, 0); if (ret < 0) { return(ret); } Inlines.OpusAssert(ret == packet_frame_size); data_ptr += size[i]; nb_samples += ret; } this.last_packet_duration = nb_samples; return(nb_samples); }
internal int opus_decode_frame(byte[] data, int data_ptr, int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec) { SilkDecoder silk_dec; CeltDecoder celt_dec; int i, silk_ret = 0, celt_ret = 0; EntropyCoder dec = new EntropyCoder(); // porting note: stack var int silk_frame_size; int pcm_silk_size; short[] pcm_silk; int pcm_transition_silk_size; short[] pcm_transition_silk; int pcm_transition_celt_size; short[] pcm_transition_celt; short[] pcm_transition = null; int redundant_audio_size; short[] redundant_audio; int audiosize; OpusMode mode; int transition = 0; int start_band; int redundancy = 0; int redundancy_bytes = 0; int celt_to_silk = 0; int c; int F2_5, F5, F10, F20; int[] window; uint redundant_rng = 0; int celt_accum; silk_dec = this.SilkDecoder; celt_dec = this.Celt_Decoder; F20 = this.Fs / 50; F10 = F20 >> 1; F5 = F10 >> 1; F2_5 = F5 >> 1; if (frame_size < F2_5) { return(OpusError.OPUS_BUFFER_TOO_SMALL); } /* Limit frame_size to avoid excessive stack allocations. */ frame_size = Inlines.IMIN(frame_size, this.Fs / 25 * 3); /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ if (len <= 1) { data = null; /* In that case, don't conceal more than what the ToC says */ frame_size = Inlines.IMIN(frame_size, this.frame_size); } if (data != null) { audiosize = this.frame_size; mode = this.mode; dec.dec_init(data, data_ptr, (uint)len); } else { audiosize = frame_size; mode = this.prev_mode; if (mode == 0) { /* If we haven't got any packet yet, all we can do is return zeros */ for (i = pcm_ptr; i < pcm_ptr + (audiosize * this.channels); i++) { pcm[i] = 0; } return(audiosize); } /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), * 10, or 20 (e.g. 12.5 or 30 ms). */ if (audiosize > F20) { do { int ret = opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(audiosize, F20), 0); if (ret < 0) { return(ret); } pcm_ptr += ret * this.channels; audiosize -= ret; } while (audiosize > 0); return(frame_size); } else if (audiosize < F20) { if (audiosize > F10) { audiosize = F10; } else if (mode != OpusMode.MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) { audiosize = F5; } } } /* In fixed-point, we can tell CELT to do the accumulation on top of the * SILK PCM buffer. This saves some stack space. */ celt_accum = ((mode != OpusMode.MODE_CELT_ONLY) && (frame_size >= F10)) ? 1 : 0; pcm_transition_silk_size = 0; pcm_transition_celt_size = 0; if (data != null && this.prev_mode > 0 && ( (mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY && (this.prev_redundancy == 0)) || (mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY)) ) { transition = 1; /* Decide where to allocate the stack memory for pcm_transition */ if (mode == OpusMode.MODE_CELT_ONLY) { pcm_transition_celt_size = F5 * this.channels; } else { pcm_transition_silk_size = F5 * this.channels; } } pcm_transition_celt = new short[pcm_transition_celt_size]; if (transition != 0 && mode == OpusMode.MODE_CELT_ONLY) { pcm_transition = pcm_transition_celt; opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0); } if (audiosize > frame_size) { /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ return(OpusError.OPUS_BAD_ARG); } else { frame_size = audiosize; } /* Don't allocate any memory when in CELT-only mode */ pcm_silk_size = (mode != OpusMode.MODE_CELT_ONLY && (celt_accum == 0)) ? Inlines.IMAX(F10, frame_size) * this.channels : 0; pcm_silk = new short[pcm_silk_size]; /* SILK processing */ if (mode != OpusMode.MODE_CELT_ONLY) { int lost_flag, decoded_samples; short[] pcm_ptr2; int pcm_ptr2_ptr = 0; if (celt_accum != 0) { pcm_ptr2 = pcm; pcm_ptr2_ptr = pcm_ptr; } else { pcm_ptr2 = pcm_silk; pcm_ptr2_ptr = 0; } if (this.prev_mode == OpusMode.MODE_CELT_ONLY) { DecodeAPI.silk_InitDecoder(silk_dec); } /* The SILK PLC cannot produce frames of less than 10 ms */ this.DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * audiosize / this.Fs); if (data != null) { this.DecControl.nChannelsInternal = this.stream_channels; if (mode == OpusMode.MODE_SILK_ONLY) { if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { this.DecControl.internalSampleRate = 8000; } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { this.DecControl.internalSampleRate = 12000; } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { this.DecControl.internalSampleRate = 16000; } else { this.DecControl.internalSampleRate = 16000; Inlines.OpusAssert(false); } } else { /* Hybrid mode */ this.DecControl.internalSampleRate = 16000; } } lost_flag = data == null ? 1 : 2 * decode_fec; decoded_samples = 0; do { /* Call SILK decoder */ int first_frame = (decoded_samples == 0) ? 1 : 0; silk_ret = DecodeAPI.silk_Decode(silk_dec, this.DecControl, lost_flag, first_frame, dec, pcm_ptr2, pcm_ptr2_ptr, out silk_frame_size); if (silk_ret != 0) { if (lost_flag != 0) { /* PLC failure should not be fatal */ silk_frame_size = frame_size; Arrays.MemSetWithOffset <short>(pcm_ptr2, 0, pcm_ptr2_ptr, frame_size * this.channels); } else { return(OpusError.OPUS_INTERNAL_ERROR); } } pcm_ptr2_ptr += (silk_frame_size * this.channels); decoded_samples += silk_frame_size; } while (decoded_samples < frame_size); } start_band = 0; if (decode_fec == 0 && mode != OpusMode.MODE_CELT_ONLY && data != null && dec.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * len) { /* Check if we have a redundant 0-8 kHz band */ if (mode == OpusMode.MODE_HYBRID) { redundancy = dec.dec_bit_logp(12); } else { redundancy = 1; } if (redundancy != 0) { celt_to_silk = dec.dec_bit_logp(1); /* redundancy_bytes will be at least two, in the non-hybrid * case due to the ec_tell() check above */ redundancy_bytes = mode == OpusMode.MODE_HYBRID ? (int)dec.dec_uint(256) + 2 : len - ((dec.tell() + 7) >> 3); len -= redundancy_bytes; /* This is a sanity check. It should never happen for a valid * packet, so the exact behaviour is not normative. */ if (len * 8 < dec.tell()) { len = 0; redundancy_bytes = 0; redundancy = 0; } /* Shrink decoder because of raw bits */ dec.storage = (uint)(dec.storage - redundancy_bytes); } } if (mode != OpusMode.MODE_CELT_ONLY) { start_band = 17; } { int endband = 21; switch (this.bandwidth) { case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND: endband = 13; break; case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND: case OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND: endband = 17; break; case OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND: endband = 19; break; case OpusBandwidth.OPUS_BANDWIDTH_FULLBAND: endband = 21; break; } celt_dec.SetEndBand(endband); celt_dec.SetChannels(this.stream_channels); } if (redundancy != 0) { transition = 0; pcm_transition_silk_size = 0; } pcm_transition_silk = new short[pcm_transition_silk_size]; if (transition != 0 && mode != OpusMode.MODE_CELT_ONLY) { pcm_transition = pcm_transition_silk; opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0); } /* Only allocation memory for redundancy if/when needed */ redundant_audio_size = redundancy != 0 ? F5 * this.channels : 0; redundant_audio = new short[redundant_audio_size]; /* 5 ms redundant frame for CELT->SILK*/ if (redundancy != 0 && celt_to_silk != 0) { celt_dec.SetStartBand(0); celt_dec.celt_decode_with_ec(data, (data_ptr + len), redundancy_bytes, redundant_audio, 0, F5, null, 0); redundant_rng = celt_dec.GetFinalRange(); } /* MUST be after PLC */ celt_dec.SetStartBand(start_band); if (mode != OpusMode.MODE_SILK_ONLY) { int celt_frame_size = Inlines.IMIN(F20, frame_size); /* Make sure to discard any previous CELT state */ if (mode != this.prev_mode && this.prev_mode > 0 && this.prev_redundancy == 0) { celt_dec.ResetState(); } /* Decode CELT */ celt_ret = celt_dec.celt_decode_with_ec(decode_fec != 0 ? null : data, data_ptr, len, pcm, pcm_ptr, celt_frame_size, dec, celt_accum); } else { if (celt_accum == 0) { for (i = pcm_ptr; i < (frame_size * this.channels) + pcm_ptr; i++) { pcm[i] = 0; } } /* For hybrid -> SILK transitions, we let the CELT MDCT * do a fade-out by decoding a silence frame */ if (this.prev_mode == OpusMode.MODE_HYBRID && !(redundancy != 0 && celt_to_silk != 0 && this.prev_redundancy != 0)) { celt_dec.SetStartBand(0); celt_dec.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, F2_5, null, celt_accum); } } if (mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0) { for (i = 0; i < frame_size * this.channels; i++) { pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], pcm_silk[i])); } } window = celt_dec.GetMode().window; /* 5 ms redundant frame for SILK->CELT */ if (redundancy != 0 && celt_to_silk == 0) { celt_dec.ResetState(); celt_dec.SetStartBand(0); celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0); redundant_rng = celt_dec.GetFinalRange(); CodecHelpers.smooth_fade(pcm, pcm_ptr + this.channels * (frame_size - F2_5), redundant_audio, this.channels * F2_5, pcm, (pcm_ptr + this.channels * (frame_size - F2_5)), F2_5, this.channels, window, this.Fs); } if (redundancy != 0 && celt_to_silk != 0) { for (c = 0; c < this.channels; c++) { for (i = 0; i < F2_5; i++) { pcm[this.channels * i + c + pcm_ptr] = redundant_audio[this.channels * i + c]; } } CodecHelpers.smooth_fade(redundant_audio, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)), pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs); } if (transition != 0) { if (audiosize >= F5) { for (i = 0; i < this.channels * F2_5; i++) { pcm[i] = pcm_transition[i]; } CodecHelpers.smooth_fade(pcm_transition, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)), pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs); } else { /* Not enough time to do a clean transition, but we do it anyway * This will not preserve amplitude perfectly and may introduce * a bit of temporal aliasing, but it shouldn't be too bad and * that's pretty much the best we can do. In any case, generating this * transition is pretty silly in the first place */ CodecHelpers.smooth_fade(pcm_transition, 0, pcm, pcm_ptr, pcm, pcm_ptr, F2_5, this.channels, window, this.Fs); } } if (this.decode_gain != 0) { int gain; gain = Inlines.celt_exp2(Inlines.MULT16_16_P15(((short)(0.5 + (6.48814081e-4f) * (((int)1) << (25)))) /*Inlines.QCONST16(6.48814081e-4f, 25)*/, this.decode_gain)); for (i = pcm_ptr; i < pcm_ptr + (frame_size * this.channels); i++) { int x; x = Inlines.MULT16_32_P16(pcm[i], gain); pcm[i] = (short)Inlines.SATURATE(x, 32767); } } if (len <= 1) { this.rangeFinal = 0; } else { this.rangeFinal = dec.rng ^ redundant_rng; } this.prev_mode = mode; this.prev_redundancy = (redundancy != 0 && celt_to_silk == 0) ? 1 : 0; return(celt_ret < 0 ? celt_ret : audiosize); }
public AudioChunk Decompress(byte[] inputPacket) { int frameSize = GetFrameSize(); short[] outputBuffer = new short[frameSize]; bool lostPacket = new Random().Next(0, 100) < _packetLoss; if (!lostPacket) { // Normal decoding _timer.Reset(); _timer.Start(); int thisFrameSize = _decoder.Decode(inputPacket, 0, inputPacket.Length, outputBuffer, 0, frameSize, false); _timer.Stop(); } else { // packet loss path _timer.Reset(); _timer.Start(); int thisFrameSize = _decoder.Decode(null, 0, 0, outputBuffer, 0, frameSize, true); _timer.Stop(); } short[] finalOutput = new short[frameSize]; Array.Copy(outputBuffer, finalOutput, finalOutput.Length); // Update statistics _statistics.Bitrate = inputPacket.Length * 8 * 48000 / 1024 / frameSize; OpusMode curMode = OpusPacketInfo.GetEncoderMode(inputPacket, 0); if (curMode == OpusMode.MODE_CELT_ONLY) { _statistics.Mode = "CELT"; } else if (curMode == OpusMode.MODE_HYBRID) { _statistics.Mode = "Hybrid"; } else if (curMode == OpusMode.MODE_SILK_ONLY) { _statistics.Mode = "SILK"; } else { _statistics.Mode = "Unknown"; } _statistics.DecodeSpeed = _frameSize / ((double)_timer.ElapsedTicks / Stopwatch.Frequency * 1000); OpusBandwidth curBandwidth = OpusPacketInfo.GetBandwidth(inputPacket, 0); if (curBandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { _statistics.Bandwidth = 8000; } else if (curBandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { _statistics.Bandwidth = 12000; } else if (curBandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { _statistics.Bandwidth = 16000; } else if (curBandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) { _statistics.Bandwidth = 24000; } else { _statistics.Bandwidth = 48000; } return new AudioChunk(finalOutput, 48000); }
public void ShotgunTest() { OpusApplication[] Applications = new OpusApplication[] { OpusApplication.OPUS_APPLICATION_AUDIO, OpusApplication.OPUS_APPLICATION_VOIP, OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY }; int[] Bitrates = new int[] { -1, 6, 16, 20, 32, 64, 500 }; int[] Channels = new int[] { 1, 2 }; int[] Complexities = new int[] { 0, 2, 4, 6, 8, 10 }; int[] SampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; double[] FrameSizes = new double[] { 2.5, 5, 10, 20, 40, 60 }; int[] PacketLosses = new int[] { 0, 20 }; OpusMode[] ForceModes = new OpusMode[] { OpusMode.MODE_AUTO, OpusMode.MODE_CELT_ONLY, OpusMode.MODE_SILK_ONLY }; bool[] DTXModes = new bool[] { false, true }; int[] VBRModes = new int[] { 0, 1, 2 }; IList <TestParameters> allTests = new List <TestParameters>(); for (int app_idx = 0; app_idx < Applications.Length; app_idx++) { for (int plc_idx = 0; plc_idx < PacketLosses.Length; plc_idx++) { for (int chan_idx = 0; chan_idx < Channels.Length; chan_idx++) { for (int sr_idx = 0; sr_idx < SampleRates.Length; sr_idx++) { for (int fs_idx = 0; fs_idx < FrameSizes.Length; fs_idx++) { for (int cpx_idx = 0; cpx_idx < Complexities.Length; cpx_idx++) { for (int bit_idx = 0; bit_idx < Bitrates.Length; bit_idx++) { for (int fm_idx = 0; fm_idx < ForceModes.Length; fm_idx++) { for (int dtx_idx = 0; dtx_idx < DTXModes.Length; dtx_idx++) { for (int vbr_idx = 0; vbr_idx < VBRModes.Length; vbr_idx++) { TestParameters newParams = new TestParameters() { Application = Applications[app_idx], Bitrate = Bitrates[bit_idx], Channels = Channels[chan_idx], Complexity = Complexities[cpx_idx], PacketLossPercent = PacketLosses[plc_idx], SampleRate = SampleRates[sr_idx], FrameSize = FrameSizes[fs_idx], ForceMode = ForceModes[fm_idx], UseDTX = DTXModes[dtx_idx] }; if (VBRModes[vbr_idx] == 0) { newParams.UseVBR = false; newParams.ConstrainedVBR = false; } else if (VBRModes[vbr_idx] == 1) { newParams.UseVBR = true; newParams.ConstrainedVBR = false; } else if (VBRModes[vbr_idx] == 2) { newParams.UseVBR = true; newParams.ConstrainedVBR = true; } // Validate params if (newParams.Bitrate > 40 || newParams.FrameSize < 10) { // No FEC outside of SILK mode if (newParams.PacketLossPercent > 0) { continue; } // No DTX outside of SILK mode if (newParams.UseDTX) { continue; } if (newParams.ForceMode == OpusMode.MODE_SILK_ONLY) { continue; } } // Constrained VBR only applies to CELT if (newParams.ForceMode == OpusMode.MODE_SILK_ONLY && newParams.ConstrainedVBR) { continue; } // 12Khz + 2.5ms triggers an opus bug for now if (newParams.SampleRate == 12000 && newParams.FrameSize < 5) { continue; } allTests.Add(newParams); } } } } } } } } } } TestParameters[] allTestsRandom = allTests.ToArray(); int numTestCases = allTests.Count; // Shuffle the test list TestParameters temp; int a; int b; Random rand = new Random(); for (int c = 0; c < numTestCases; c++) { a = rand.Next(numTestCases); b = rand.Next(numTestCases); temp = allTestsRandom[a]; allTestsRandom[a] = allTestsRandom[b]; allTestsRandom[b] = temp; } int testsRun = 0; foreach (TestParameters p in allTestsRandom) { testsRun++; TestResults response = TestDriver.RunTest(p, GetTestSample(p)); Assert.IsTrue(response.Passed); if (testsRun > 50) { break; } } }
public AudioChunk Decompress(byte[] inputPacket) { int frameSize = GetFrameSize(); short[] outputBuffer = new short[frameSize]; bool lostPacket = new Random().Next(0, 100) < _packetLoss; if (!lostPacket) { // normal decoding _timer.Reset(); _timer.Start(); unsafe { fixed(short *bdec = outputBuffer) { IntPtr decodedPtr = new IntPtr((byte *)(bdec)); int thisFrameSize = opus_decode(_decoder, inputPacket, inputPacket.Length, decodedPtr, frameSize, 0); } } _timer.Stop(); } else { // packet loss path _timer.Reset(); _timer.Start(); unsafe { fixed(short *bdec = outputBuffer) { IntPtr decodedPtr = new IntPtr((byte *)(bdec)); int thisFrameSize = opus_decode(_decoder, null, 0, decodedPtr, frameSize, 1); } } _timer.Stop(); } short[] finalOutput = new short[frameSize]; Array.Copy(outputBuffer, finalOutput, finalOutput.Length); // Update statistics _statistics.Bitrate = inputPacket.Length * 8 * 48000 / 1024 / frameSize; OpusMode curMode = OpusPacketInfo.GetEncoderMode(inputPacket, 0); if (curMode == OpusMode.MODE_CELT_ONLY) { _statistics.Mode = "CELT"; } else if (curMode == OpusMode.MODE_HYBRID) { _statistics.Mode = "Hybrid"; } else if (curMode == OpusMode.MODE_SILK_ONLY) { _statistics.Mode = "SILK"; } else { _statistics.Mode = "Unknown"; } _statistics.DecodeSpeed = _frameSize / ((double)_timer.ElapsedTicks / Stopwatch.Frequency * 1000); return(new AudioChunk(finalOutput, 48000)); }