diff --git a/celt/celt.c b/celt/celt.c
index 50cc434f..ad487349 100644
--- a/celt/celt.c
+++ b/celt/celt.c
@@ -2695,7 +2695,7 @@ int opus_custom_decoder_ctl(CELTDecoder * restrict st, int request, ...)
break;
case CELT_GET_AND_CLEAR_ERROR_REQUEST:
{
- int *value = va_arg(ap, int*);
+ int *value = va_arg(ap, opus_int32*);
if (value==NULL)
goto bad_arg;
*value=st->error;
@@ -2704,7 +2704,7 @@ int opus_custom_decoder_ctl(CELTDecoder * restrict st, int request, ...)
break;
case OPUS_GET_LOOKAHEAD_REQUEST:
{
- int *value = va_arg(ap, int*);
+ int *value = va_arg(ap, opus_int32*);
if (value==NULL)
goto bad_arg;
*value = st->overlap/st->downsample;
@@ -2717,6 +2717,14 @@ int opus_custom_decoder_ctl(CELTDecoder * restrict st, int request, ...)
((char*)&st->DECODER_RESET_START - (char*)st));
}
break;
+ case OPUS_GET_PITCH_REQUEST:
+ {
+ int *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value = st->postfilter_period;
+ }
+ break;
#ifdef OPUS_BUILD
case CELT_GET_MODE_REQUEST:
{
diff --git a/celt/opus_defines.h b/celt/opus_defines.h
index c72edcc3..361a5843 100644
--- a/celt/opus_defines.h
+++ b/celt/opus_defines.h
@@ -103,6 +103,7 @@ extern "C" {
#define OPUS_SET_DTX_REQUEST 4016
#define OPUS_GET_DTX_REQUEST 4017
#define OPUS_GET_FINAL_RANGE_REQUEST 4031
+#define OPUS_GET_PITCH_REQUEST 4033
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
@@ -343,11 +344,21 @@ extern "C" {
* The encoder and decoder state should be identical after coding a payload
* (assuming no data corruption or software bugs)
*
- * @param[out] x opus_int32*: Entropy coder state
+ * @param[out] x opus_uint32*: Entropy coder state
*
* @hideinitializer */
#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
+/** Gets the pitch of the last decoded frame, if available.
+ * This can be used for any post-processing algorithm requiring the use of pitch,
+ * e.g. time stretching/shortening. If the last frame was not voiced, or if the
+ * pitch was not coded in the frame, then zero is returned.
+ *
+ * @param[out] x opus_int32*: pitch period at 48 kHz (or 0 if not available)
+ *
+ * @hideinitializer */
+#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
+
/**@}*/
/** @defgroup libinfo Opus library information functions
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 55be0a76..254548be 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -39,6 +39,8 @@
#include "float_cast.h"
#include "opus_private.h"
#include "os_support.h"
+#include "silk_structs.h"
+#include "silk_define.h"
struct OpusDecoder {
int celt_dec_offset;
@@ -737,6 +739,12 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
{
int ret = OPUS_OK;
va_list ap;
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+
va_start(ap, request);
@@ -756,12 +764,6 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
break;
case OPUS_RESET_STATE:
{
- void *silk_dec;
- CELTDecoder *celt_dec;
-
- silk_dec = (char*)st+st->silk_dec_offset;
- celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
-
OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
sizeof(OpusDecoder)-
((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
@@ -772,6 +774,22 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
st->frame_size = st->Fs/400;
}
break;
+ case OPUS_GET_PITCH_REQUEST:
+ {
+ int *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ if (st->prev_mode == MODE_CELT_ONLY)
+ celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
+ else
+ *value = ((silk_decoder_state*)silk_dec)->indices.signalType == TYPE_VOICED
+ ? ((silk_decoder_state*)silk_dec)->lagPrev*48/((silk_decoder_state*)silk_dec)->fs_kHz
+ : 0;
+ }
+ break;
default:
/*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
ret = OPUS_UNIMPLEMENTED;