示例#1
0
Error AudioStreamPlaybackOpus::set_file(const String &p_file) {
	file=p_file;
	stream_valid=false;
	Error err;
	f=FileAccess::open(file,FileAccess::READ,&err);

	if (err) {
		ERR_FAIL_COND_V( err, err );
	}

	int _err;

	opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);

	switch (_err) {
		case OP_EREAD: { // - Can't read the file.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_CANT_READ );
		} break;
		case OP_EVERSION: // - Unrecognized version number.
		case OP_ENOTFORMAT: // - Stream is not Opus data.
		case OP_EIMPL : { // - Stream used non-implemented feature.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
		} break;
		case OP_EBADLINK: // - Failed to find old data after seeking.
		case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
		case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_CORRUPT );
		} break;
		case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_BUG );
		} break;
	}

	const OpusHead *oinfo = op_head(opus_file,-1);

	stream_channels=oinfo->channel_count;
	pre_skip=oinfo->pre_skip;
	frames_mixed=pre_skip;
	ogg_int64_t len = op_pcm_total(opus_file,-1);
	if(len < 0) {
		length = 0;
	} else {
		length=(len/osrate);
	}

	op_free(opus_file);
	memdelete(f);
	f=NULL;
	stream_valid=true;


	return OK;
}
示例#2
0
/*
 * et_opus_read_file_info:
 * @file: file to read info from
 * @ETFileInfo: ET_File_Info to put information into
 * @error: a GError or %NULL
 *
 * Read header information of an Opus file.
 *
 * Returns: %TRUE if successful otherwise %FALSE
 */
gboolean
et_opus_read_file_info (GFile *gfile, ET_File_Info *ETFileInfo,
                        GError **error)
{
    OggOpusFile *file;
    const OpusHead* head;
    GFileInfo *info;

    g_return_val_if_fail (gfile != NULL && ETFileInfo != NULL, FALSE);
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

    file = et_opus_open_file (gfile, error);

    if (!file)
    {
        g_assert (error == NULL || *error != NULL);
        return FALSE;
    }

    /* FIXME: Improve error-checking. */
    head = op_head (file, -1);
    /* TODO: Read the vendor string from the Vorbis comment? */
    ETFileInfo->version = head->version;
    ETFileInfo->bitrate = op_bitrate (file, -1) / 1000;
    ETFileInfo->mode = head->channel_count;

    /* All Opus audio is encoded at 48 kHz, but the input sample rate can
     * differ, and then input_sample_rate will be set. */
    if (head->input_sample_rate != 0)
    {
        ETFileInfo->samplerate = head->input_sample_rate;
    }
    else
    {
        ETFileInfo->samplerate = 48000;
    }

    ETFileInfo->duration = op_pcm_total (file, -1) / 48000;
    op_free (file);

    info = g_file_query_info (gfile, G_FILE_ATTRIBUTE_STANDARD_SIZE,
                              G_FILE_QUERY_INFO_NONE, NULL, NULL);

    if (info)
    {
        ETFileInfo->size = g_file_info_get_size (info);
        g_object_unref (info);
    }
    else
    {
        ETFileInfo->size = 0;
    }

    g_assert (error == NULL || *error == NULL);
    return TRUE;
}
示例#3
0
static int
opusdec_read_metadata (DB_playItem_t *it) {
    int res = -1;

    DB_FILE *fp = NULL;
    OggOpusFile *opusfile = NULL;
    const OpusHead *head = NULL;

    deadbeef->pl_lock ();
    const char *uri = strdupa (deadbeef->pl_find_meta (it, ":URI"));
    deadbeef->pl_unlock ();
    fp = deadbeef->fopen (uri);
    if (!fp) {
        goto error;
    }
    if (fp->vfs->is_streaming ()) {
        goto error;
    }

    opusfile = opus_file_open (fp);
    if (!opusfile) {
        goto error;
    }

    int tracknum = deadbeef->pl_find_meta_int (it, ":TRACKNUM", -1);
    head = op_head (opusfile, tracknum);
    if (!head) {
        goto error;
    }

    if (update_vorbis_comments (it, opusfile, tracknum)) {
        goto error;
    }

    res = 0;
error:
    if (opusfile) {
        op_free (opusfile);
    }
    if (fp) {
        deadbeef->fclose (fp);
    }
    return res;
}
示例#4
0
static bool
new_streaming_link(opusdec_info_t *info, const int new_link)
{
    if (!info->info.file->vfs->is_streaming () || new_link < 0) {
        return false;
    }

    update_vorbis_comments(info->it, info->opusfile, new_link);
    send_event(info->it, DB_EV_SONGSTARTED);
    send_event(info->it, DB_EV_TRACKINFOCHANGED);
    deadbeef->sendmessage(DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
    info->cur_bit_stream = new_link;

    const OpusHead *head = op_head (info->opusfile, new_link);
    if (head && info->info.fmt.channels != head->channel_count) {
        info->info.fmt.channels = head->channel_count;
        deadbeef->pl_set_meta_int (info->it, ":CHANNELS", head->channel_count);
        return true;
    }

    return false;
}
示例#5
0
static void
xmms_opus_read_metadata (xmms_xform_t *xform, xmms_opus_data_t *data)
{
	data->opushead = op_head (data->opusfile, -1);
	data->opustags = op_tags (data->opusfile, -1);
	data->channels = op_channel_count (data->opusfile, -1);

	gint i;

	if (!data->opustags)
		return;

	for (i = 0; i < data->opustags->comments; i++) {
		const gchar *ptr, *entry;
		gsize length;
		gchar key[64];

		entry = data->opustags->user_comments[i];
		length = data->opustags->comment_lengths[i];

		if (entry == NULL || *entry == '\0')
			continue;

		/* check whether it's a valid comment */
		ptr = memchr (entry, '=', length);
		if (ptr == NULL)
			continue;

		ptr++;

		g_strlcpy (key, entry, MIN (ptr - entry, sizeof (key)));

		if (!xmms_xform_metadata_mapper_match (xform, key, ptr, length - (ptr - entry))) {
			XMMS_DBG ("Unhandled tag '%s'", entry);
		}

	}
}
/*
=================
S_OggOpus_CodecOpenStream
=================
*/
snd_stream_t *S_OggOpus_CodecOpenStream( const char *filename )
{
	snd_stream_t *stream;

	// Opus codec control structure
	OggOpusFile *of;

	// some variables used to get informations about the file
	const OpusHead *opusInfo;
	ogg_int64_t numSamples;

	// check if input is valid
	if ( !filename )
	{
		return NULL;
	}

	// Open the stream
	stream = S_CodecUtilOpen( filename, &opus_codec );

	if ( !stream )
	{
		return NULL;
	}

	// open the codec with our callbacks and stream as the generic pointer
	of = op_open_callbacks( stream, &S_OggOpus_Callbacks, NULL, 0, NULL );

	if ( !of )
	{
		S_CodecUtilClose( &stream );

		return NULL;
	}

	// the stream must be seekable
	if ( !op_seekable( of ) )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		return NULL;
	}

	// get the info about channels and rate
	opusInfo = op_head( of, -1 );

	if ( !opusInfo )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		return NULL;
	}

	if ( opusInfo->stream_count != 1 )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		Com_Printf( "Only Ogg Opus files with one stream are support\n" );
		return NULL;
	}

	if ( opusInfo->channel_count != 1 && opusInfo->channel_count != 2 )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		Com_Printf( "Only mono and stereo Ogg Opus files are supported\n" );
		return NULL;
	}

	// get the number of sample-frames in the file
	numSamples = op_pcm_total( of, -1 );

	// fill in the info-structure in the stream
	stream->info.rate = 48000;
	stream->info.width = OPUS_SAMPLEWIDTH;
	stream->info.channels = opusInfo->channel_count;
	stream->info.samples = numSamples;
	stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
	stream->info.dataofs = 0;

	// We use stream->pos for the file pointer in the compressed ogg file
	stream->pos = 0;

	// We use the generic pointer in stream for the opus codec control structure
	stream->ptr = of;

	return stream;
}
示例#7
0
AudioData LoadOpusCodec(std::string filename)
{
	std::string audioFile;
	try
	{
		audioFile = FS::PakPath::ReadFile(filename);
	}
	catch (std::system_error& err)
	{
		audioLogs.Warn("Failed to open %s: %s", filename, err.what());
		return AudioData();
	}

	OpusDataSource dataSource = {&audioFile, 0};
	OggOpusFile* opusFile = op_open_callbacks(&dataSource, &Opus_Callbacks, nullptr, 0, nullptr);

	if (!opusFile) {
		audioLogs.Warn("Error while reading %s", filename);
		return AudioData();
	}

	const OpusHead* opusInfo = op_head(opusFile, -1);

	if (!opusInfo) {
		op_free(opusFile);
		audioLogs.Warn("Could not read OpusHead in %s", filename);
		return AudioData();
	}

	if (opusInfo->stream_count != 1) {
		op_free(opusFile);
		audioLogs.Warn("Only one stream is supported in Opus files: %s", filename);
		return AudioData();
	}

	if (opusInfo->channel_count != 1 && opusInfo->channel_count != 2) {
		op_free(opusFile);
		audioLogs.Warn("Only mono and stereo Opus files are supported: %s", filename);
		return AudioData();
	}

	const int sampleWidth = 2;

	int sampleRate = 48000;
	int numberOfChannels = opusInfo->channel_count;

	// The buffer is big enough to hold 120ms worth of samples per channel
	opus_int16* buffer = new opus_int16[numberOfChannels * 5760];
	int samplesPerChannelRead = 0;

	std::vector<opus_int16> samples;

	while ((samplesPerChannelRead =
	            op_read(opusFile, buffer, sampleWidth * numberOfChannels * 5760, nullptr)) > 0) {
		std::copy_n(buffer, samplesPerChannelRead * numberOfChannels, std::back_inserter(samples));
	}

	op_free(opusFile);

	char* rawSamples = new char[sampleWidth * samples.size()];
	std::copy_n(reinterpret_cast<char*>(samples.data()), sampleWidth * samples.size(), rawSamples);

	return AudioData(sampleRate, sampleWidth, numberOfChannels, samples.size() * sampleWidth,
	                 rawSamples);
}
示例#8
0
文件: opus.c 项目: brigittebigi/sppas
static PyObject*
OpusDecoder_read(decoders_OpusDecoder* self, PyObject *args)
{
    static opus_int16 pcm[BUF_SIZE];
    int pcm_frames_read;

    if (self->closed) {
        PyErr_SetString(PyExc_ValueError, "stream is closed");
        return NULL;
    }

    if ((pcm_frames_read = op_read(self->opus_file,
                                   pcm,
                                   BUF_SIZE,
                                   NULL)) >= 0) {
        const int channel_count = op_head(self->opus_file, -1)->channel_count;
        int i;
        pcm_FrameList *framelist = new_FrameList(self->audiotools_pcm,
                                                 channel_count,
                                                 BITS_PER_SAMPLE,
                                                 pcm_frames_read);
        int *samples = framelist->samples;

        for (i = 0; i < pcm_frames_read * channel_count; i++) {
            samples[i] = pcm[i];
        }

        /*reorder channels to .wav order if necessary*/
        switch (self->channel_count) {
        case 1:
        case 2:
        default:
            /*no change*/
            break;
        case 3:
            /*fL fC fR -> fL fR fC*/
            swap_channel_data(samples, 1, 2,
                              self->channel_count,
                              (unsigned)pcm_frames_read);
            break;
        case 4:
            /*fL fR bL bR -> fL fR bL bR*/
            /*no change*/
            break;
        case 5:
            /*fL fC fR bL bR -> fL fR fC bL bR*/
            swap_channel_data(samples, 1, 2,
                              self->channel_count,
                              (unsigned)pcm_frames_read);
            break;
        case 6:
            /*fL fC fR bL bR LFE -> fL fR fC bL bR LFE*/
            swap_channel_data(samples, 1, 2,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC bL bR LFE -> fL fR fC LFE bR bL*/
            swap_channel_data(samples, 3, 5,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC LFE bR bL -> fL fR fC LFE bL bR*/
            swap_channel_data(samples, 4, 5,
                              self->channel_count,
                              (unsigned)pcm_frames_read);
            break;
        case 7:
            /*fL fC fR sL sR bC LFE -> fL fR fC sL sR bC LFE*/
            swap_channel_data(samples, 1, 2,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC sL sR bC LFE -> fL fR fC LFE sR bC sL*/
            swap_channel_data(samples, 3, 6,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC LFE sR bC sL -> fL fR fC LFE bC sR sL*/
            swap_channel_data(samples, 4, 5,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC LFE bC sR sL -> fL fR fC LFE bC sL sR*/
            swap_channel_data(samples, 5, 6,
                              self->channel_count,
                              (unsigned)pcm_frames_read);
            break;
        case 8:
            /*fL fC fR sL sR bL bR LFE -> fL fR fC sL sR bL bR LFE*/
            swap_channel_data(samples, 1, 2,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC sL sR bL bR LFE -> fL fR fC LFE sR bL bR sL*/
            swap_channel_data(samples, 3, 6,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC LFE sR bL bR sL -> fL fR fC LFE bL sR bR sL*/
            swap_channel_data(samples, 4, 5,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC LFE bL sR bR sL -> fL fR fC LFE bL bR sR sL*/
            swap_channel_data(samples, 5, 6,
                              self->channel_count,
                              (unsigned)pcm_frames_read);

            /*fL fR fC LFE bL bR sR sL -> fL fR fC LFE bL bR sL sR*/
            swap_channel_data(samples, 6, 7,
                              self->channel_count,
                              (unsigned)pcm_frames_read);
            break;
        }

        return (PyObject*)framelist;
    } else {
        /*some sort of read error occurred*/
        PyErr_SetString(PyExc_ValueError, "error reading from file");
        return NULL;
    }
}
示例#9
0
static DB_playItem_t *
opusdec_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
    DB_FILE *fp = deadbeef->fopen (fname);
    if (!fp) {
        return NULL;
    }
    int64_t fsize = deadbeef->fgetlength (fp);
    if (fp->vfs->is_streaming ()) {
        DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
        deadbeef->plt_set_item_duration (plt, it, -1);
        deadbeef->pl_add_meta (it, "title", NULL);
        after = deadbeef->plt_insert_item (plt, after, it);
        deadbeef->pl_item_unref (it);
        deadbeef->fclose (fp);
        return after;
    }

    OggOpusFile *opusfile = opus_file_open (fp);
    if (!opusfile) {
        deadbeef->fclose (fp);
        return NULL;
    }

    long nstreams = op_link_count (opusfile);
    int64_t currentsample = 0;
    for (int stream = 0; stream < nstreams; stream++) {
        const OpusHead *head = op_head (opusfile, stream);
        if (!head) {
            continue;
        }
        int64_t totalsamples = op_pcm_total (opusfile, stream);
        const float duration = totalsamples / 48000.f;

        DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
        deadbeef->pl_set_meta_int (it, ":TRACKNUM", stream);
        deadbeef->plt_set_item_duration (plt, it, duration);
        if (nstreams > 1) {
            deadbeef->pl_item_set_startsample (it, currentsample);
            deadbeef->pl_item_set_endsample (it, currentsample + totalsamples - 1);
            deadbeef->pl_set_item_flags (it, DDB_IS_SUBTRACK);
        }

        if (update_vorbis_comments (it, opusfile, stream))
            continue;
        int samplerate = 48000;

        int64_t startsample = deadbeef->pl_item_get_startsample (it);
        int64_t endsample = deadbeef->pl_item_get_endsample (it);

        const off_t start_offset = sample_offset(opusfile, startsample-1);
        const off_t end_offset = sample_offset(opusfile, endsample);
        char *filetype = NULL;
        const off_t stream_size = oggedit_opus_stream_info(deadbeef->fopen(fname), start_offset, end_offset, &filetype);
        if (filetype) {
            deadbeef->pl_replace_meta(it, ":FILETYPE", filetype);
            free(filetype);
        }
        if (stream_size > 0) {
            set_meta_ll(it, ":OPUS_STREAM_SIZE", stream_size);
            deadbeef->pl_set_meta_int(it, ":BITRATE", 8.f * samplerate * stream_size / totalsamples / 1000);
        }
        set_meta_ll (it, ":FILE_SIZE", fsize);
        deadbeef->pl_set_meta_int (it, ":CHANNELS", head->channel_count);
        deadbeef->pl_set_meta_int (it, ":SAMPLERATE", samplerate);

        if (nstreams == 1) {
            DB_playItem_t *cue = deadbeef->plt_process_cue (plt, after, it,  totalsamples, samplerate);
            if (cue) {
                deadbeef->pl_item_unref (it);
                op_free(opusfile);
                deadbeef->fclose (fp);
                return cue;
            }
        }
        else {
            currentsample += totalsamples;
        }

        after = deadbeef->plt_insert_item (plt, after, it);
        deadbeef->pl_item_unref (it);
    }
    op_free(opusfile);
    deadbeef->fclose (fp);
    return after;
}
示例#10
0
static int
opusdec_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    opusdec_info_t *info = (opusdec_info_t *)_info;

    if (!info->info.file) {
        deadbeef->pl_lock ();
	const char *uri = strdupa (deadbeef->pl_find_meta (it, ":URI"));
        deadbeef->pl_unlock ();
        DB_FILE *fp = deadbeef->fopen (uri);

        if (!fp) {
            return -1;
        }
        info->info.file = fp;
        info->it = it;
        deadbeef->pl_item_ref (it);
    }

    info->opusfile = opus_file_open (info->info.file);
    if (!info->opusfile) {
        return -1;
    }

    const OpusHead *head = op_head (info->opusfile, 0);

    if (head->channel_count > 8) {
        trace ("opus: the track has %d channels, but 8 is max supported.\n");
        return -1;
    }

    // take this parameters from your input file
    // we set constants for clarity sake
    _info->fmt.bps = 32;
    _info->fmt.is_float = 1;
    _info->fmt.channels = head->channel_count;
    _info->fmt.samplerate  = 48000;
    if (head->mapping_family == 1) {
        info->channelmap = oggedit_vorbis_channel_map (head->channel_count);
    }

    for (int i = 0; i < (_info->fmt.channels&0x1f); i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    _info->readpos = 0;
    _info->plugin = &plugin;

    // set all gain adjustment to 0, because deadbeef is performing that.
    op_set_gain_offset (info->opusfile, OP_ABSOLUTE_GAIN, 0);

    if (info->info.file->vfs->is_streaming ()) {
        deadbeef->pl_item_set_startsample (it, 0);
        if (deadbeef->pl_get_item_duration (it) < 0) {
            deadbeef->pl_item_set_endsample (it, -1);
        }
        else {
            deadbeef->pl_item_set_endsample (it, op_pcm_total (info->opusfile, -1) - 1);
        }

        if (update_vorbis_comments (it, info->opusfile, -1))
            return -1;

        deadbeef->pl_set_meta_int(it, ":TRACKNUM", 0);
    }
    else {
        opusdec_seek_sample (_info, 0);
    }

    deadbeef->pl_replace_meta (it, "!FILETYPE", "Ogg Opus");
    deadbeef->pl_set_meta_int (it, ":CHANNELS", head->channel_count);

    info->cur_bit_stream = -1;

    return 0;
}
示例#11
0
static int
update_vorbis_comments (DB_playItem_t *it, OggOpusFile *opusfile, const int tracknum) {
    const OpusTags *vc = op_tags (opusfile, tracknum);
    if (!vc) {
        return -1;
    }

    deadbeef->pl_delete_all_meta (it);

    for (int i = 0; i < vc->comments; i++) {
        char *tag = strdup(vc->user_comments[i]);
        char *value;
        if (tag && (value = strchr(tag, '='))
#ifdef ANDROID
            && strlen (value) < 4000
#endif
            ) {
            // skip the ignored RG fields, and the picture
            if (_is_replaygain_tag (it, tag) || !strcasecmp (tag, "METADATA_BLOCK_PICTURE")) {
                free (tag);
                continue;
            }
            *value++ = '\0';
            deadbeef->pl_append_meta(it, oggedit_map_tag(tag, "tag2meta"), value);
        }
        if (tag) {
            free(tag);
        }
    }

    const char *r128_trackgain = deadbeef->pl_find_meta (it, "R128_TRACK_GAIN");
    if (r128_trackgain) {
        int trackgain = atoi (r128_trackgain) + op_head (opusfile, tracknum)->output_gain;
        if (trackgain != 0) {
            deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, trackgain / 256.0f + 5.0f);
            deadbeef->pl_delete_meta (it, "R128_TRACK_GAIN");
        }
    }

    int albumgain = op_head (opusfile, tracknum)->output_gain;
    const char *r128_albumgain = deadbeef->pl_find_meta (it, "R128_ALBUM_GAIN");
    if (r128_albumgain) {
        albumgain += atoi (r128_albumgain);
        deadbeef->pl_delete_meta (it, "R128_ALBUM_GAIN");
    }
    if (albumgain != 0) {
        deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, albumgain / 256.0f + 5.0f);
    }

    char s[100];
    int output_gain = op_head (opusfile, tracknum)->output_gain;
    snprintf (s, sizeof (s), "%0.2f dB", output_gain / 256.0f + 5.0f);
    deadbeef->pl_replace_meta (it, ":OPUS_HEADER_GAIN", s);

    deadbeef->pl_set_meta_int (it, ":SAMPLERATE_ORIGINAL", op_head (opusfile, tracknum)->input_sample_rate);

    deadbeef->pl_add_meta (it, "title", NULL);
    uint32_t f = deadbeef->pl_get_item_flags (it);
    f &= ~DDB_TAG_MASK;
    f |= DDB_TAG_VORBISCOMMENTS;
    deadbeef->pl_set_item_flags (it, f);
    ddb_playlist_t *plt = deadbeef->plt_get_curr ();
    if (plt) {
        deadbeef->plt_modified (plt);
        deadbeef->plt_unref (plt);
    }

    return 0;
}
示例#12
0
void VoiceMessagesLoader::onLoad(AudioData *audio) {
	bool started = false;
	int32 audioindex = -1;
	Loader *l = 0;
	Loaders::iterator j = _loaders.end();
	{
		QMutexLocker lock(&voicemsgsMutex);
		VoiceMessages *voice = audioVoice();
		if (!voice) return;

		for (int32 i = 0; i < AudioVoiceMsgSimultaneously; ++i) {
			VoiceMessages::Msg &m(voice->_data[i]);
			if (m.audio != audio || !m.loading) continue;

			audioindex = i;
			j = _loaders.find(audio);
			if (j != _loaders.end() && (j.value()->fname != m.fname || j.value()->data.size() != m.data.size())) {
				delete j.value();
				_loaders.erase(j);
				j = _loaders.end();
			}
			if (j == _loaders.end()) {
				l = (j = _loaders.insert(audio, new Loader())).value();
				l->fname = m.fname;
				l->data = m.data;
				
				int ret;
				if (m.data.isEmpty()) {
					l->file = op_open_file(m.fname.toUtf8().constData(), &ret);
				} else {
					l->file = op_open_memory((const unsigned char*)m.data.constData(), m.data.size(), &ret);
				}
				if (!l->file) {
					LOG(("Audio Error: op_open_file failed for '%1', data size '%2', error code %3").arg(m.fname).arg(m.data.size()).arg(ret));
					m.state = VoiceMessageStopped;
					return loadError(j);
				}
				ogg_int64_t duration = op_pcm_total(l->file, -1);
				if (duration < 0) {
					LOG(("Audio Error: op_pcm_total failed to get full duration for '%1', data size '%2', error code %3").arg(m.fname).arg(m.data.size()).arg(duration));
					m.state = VoiceMessageStopped;
					return loadError(j);
				}
				m.duration = duration;
				m.skipStart = 0;
				m.skipEnd = duration;
				m.position = 0;
				m.started = 0;
				started = true;
			} else {
				if (!m.skipEnd) continue;
				l = j.value();
			}
			break;
		}
	}

	if (j == _loaders.end()) {
		LOG(("Audio Error: trying to load part of audio, that is not playing at the moment"));
		emit error(audio);
		return;
	}
	if (started) {
		l->pcm_offset = op_pcm_tell(l->file);
		l->pcm_print_offset = l->pcm_offset - AudioVoiceMsgFrequency;
	}

	bool finished = false;
    DEBUG_LOG(("Audio Info: reading buffer for file '%1', data size '%2', current pcm_offset %3").arg(l->fname).arg(l->data.size()).arg(l->pcm_offset));

	QByteArray result;
	int64 samplesAdded = 0;
	while (result.size() < AudioVoiceMsgBufferSize) {
		opus_int16 pcm[AudioVoiceMsgFrequency * AudioVoiceMsgChannels];

		int ret = op_read_stereo(l->file, pcm, sizeof(pcm) / sizeof(*pcm));
		if (ret < 0) {
			{
				QMutexLocker lock(&voicemsgsMutex);
				VoiceMessages *voice = audioVoice();
				if (voice) {
					VoiceMessages::Msg &m(voice->_data[audioindex]);
					if (m.audio == audio) {
						m.state = VoiceMessageStopped;
					}
				}
			}
			LOG(("Audio Error: op_read_stereo failed, error code %1").arg(ret));
			return loadError(j);
		}

		int li = op_current_link(l->file);
		if (li != l->prev_li) {
			const OpusHead *head = op_head(l->file, li);
			const OpusTags *tags = op_tags(l->file, li);
			for (int32 ci = 0; ci < tags->comments; ++ci) {
				const char *comment = tags->user_comments[ci];
				if (opus_tagncompare("METADATA_BLOCK_PICTURE", 22, comment) == 0) {
					OpusPictureTag pic;
					int err = opus_picture_tag_parse(&pic, comment);
					if (err >= 0) {
						opus_picture_tag_clear(&pic);
					}
				}
			}
			if (!op_seekable(l->file)) {
				l->pcm_offset = op_pcm_tell(l->file) - ret;
			}
		}
		if (li != l->prev_li || l->pcm_offset >= l->pcm_print_offset + AudioVoiceMsgFrequency) {
			l->pcm_print_offset = l->pcm_offset;
		}
		l->pcm_offset = op_pcm_tell(l->file);

		if (!ret) {
			DEBUG_LOG(("Audio Info: read completed"));
			finished = true;
			break;
		}
		result.append((const char*)pcm, sizeof(*pcm) * ret * AudioVoiceMsgChannels);
		l->prev_li = li;
		samplesAdded += ret;

		{
			QMutexLocker lock(&voicemsgsMutex);
			VoiceMessages *voice = audioVoice();
			if (!voice) return;

			VoiceMessages::Msg &m(voice->_data[audioindex]);
			if (m.audio != audio || !m.loading || m.fname != l->fname || m.data.size() != l->data.size()) {
				LOG(("Audio Error: playing changed while loading"));
				m.state = VoiceMessageStopped;
				return loadError(j);
			}
		}
	}

	QMutexLocker lock(&voicemsgsMutex);
	VoiceMessages *voice = audioVoice();
	if (!voice) return;

	VoiceMessages::Msg &m(voice->_data[audioindex]);
	if (m.audio != audio || !m.loading || m.fname != l->fname || m.data.size() != l->data.size()) {
		LOG(("Audio Error: playing changed while loading"));
		m.state = VoiceMessageStopped;
		return loadError(j);
	}

	if (started) {
		if (m.source) {
			alSourceStop(m.source);
			for (int32 i = 0; i < 3; ++i) {
				if (m.samplesCount[i]) {
					alSourceUnqueueBuffers(m.source, 1, m.buffers + i);
					m.samplesCount[i] = 0;
				}
			}
			m.nextBuffer = 0;
		}
	}
	if (samplesAdded) {
		if (!m.source) {
			alGenSources(1, &m.source);
			alSourcef(m.source, AL_PITCH, 1.f);
			alSourcef(m.source, AL_GAIN, 1.f);
			alSource3f(m.source, AL_POSITION, 0, 0, 0);
			alSource3f(m.source, AL_VELOCITY, 0, 0, 0);
			alSourcei(m.source, AL_LOOPING, 0);
		}
		if (!m.buffers[m.nextBuffer]) alGenBuffers(3, m.buffers);
		if (!_checkALError()) {
			m.state = VoiceMessageStopped;
			return loadError(j);
		}

		if (m.samplesCount[m.nextBuffer]) {
			alSourceUnqueueBuffers(m.source, 1, m.buffers + m.nextBuffer);
			m.skipStart += m.samplesCount[m.nextBuffer];
		}

		m.samplesCount[m.nextBuffer] = samplesAdded;
		alBufferData(m.buffers[m.nextBuffer], AL_FORMAT_STEREO16, result.constData(), result.size(), AudioVoiceMsgFrequency);
		alSourceQueueBuffers(m.source, 1, m.buffers + m.nextBuffer);
		m.skipEnd -= samplesAdded;

		m.nextBuffer = (m.nextBuffer + 1) % 3;

		if (!_checkALError()) {
			m.state = VoiceMessageStopped;
			return loadError(j);
		}
	} else {
		finished = true;
	}
	if (finished) {
		m.skipEnd = 0;
		m.duration = m.skipStart + m.samplesCount[0] + m.samplesCount[1] + m.samplesCount[2];
	}
	m.loading = false;
	if (m.state == VoiceMessageResuming || m.state == VoiceMessagePlaying || m.state == VoiceMessageStarting) {
		ALint state = AL_INITIAL;
		alGetSourcei(m.source, AL_SOURCE_STATE, &state);
		if (_checkALError()) {
			if (state != AL_PLAYING) {
				alSourcePlay(m.source);
				emit needToCheck();
			}
		}
	}
}
示例#13
0
static qboolean S_OPUS_CodecOpenStream (snd_stream_t *stream)
{
	OggOpusFile *opFile;
	const OpusHead *op_info;
	long numstreams;
	int res;

	opFile = op_open_callbacks(&stream->fh, &opc_qfs, NULL, 0, &res);
	if (!opFile)
	{
		Con_Printf("%s is not a valid Opus file (error %i).\n",
				stream->name, res);
		goto _fail;
	}

	stream->priv = opFile;

	if (!op_seekable(opFile))
	{
		Con_Printf("Opus stream %s not seekable.\n", stream->name);
		goto _fail;
	}

	op_info = op_head(opFile, -1);
	if (!op_info)
	{
		Con_Printf("Unable to get stream information for %s.\n", stream->name);
		goto _fail;
	}

	/* FIXME: handle section changes */
	numstreams = op_info->stream_count;
	if (numstreams != 1)
	{
		Con_Printf("More than one (%ld) stream in %s\n",
					(long)op_info->stream_count, stream->name);
		goto _fail;
	}

	if (op_info->channel_count != 1 && op_info->channel_count != 2)
	{
		Con_Printf("Unsupported number of channels %d in %s\n",
					op_info->channel_count, stream->name);
		goto _fail;
	}

	/* All Opus audio is coded at 48 kHz, and should also be decoded
	 * at 48 kHz for playback: info->input_sample_rate only tells us
	 * the sampling rate of the original input before opus encoding.
	 * S_RawSamples() shall already downsample this, as necessary.  */
	stream->info.rate = 48000;
	stream->info.channels = op_info->channel_count;
	/* op_read() yields 16-bit output using native endian ordering: */
	stream->info.bits = 16;
	stream->info.width = 2;

	return true;
_fail:
	if (opFile)
		op_free(opFile);
	return false;
}
示例#14
0
/*the OpusDecoder.read() method*/
static PyObject*
OpusDecoder_read(decoders_OpusDecoder* self, PyObject *args)
{
    static opus_int16 pcm[BUF_SIZE];
    int pcm_frames_read;

    if (self->closed) {
        PyErr_SetString(PyExc_ValueError, "stream is closed");
        return NULL;
    }

    if ((pcm_frames_read = op_read(self->opus_file,
                                   pcm,
                                   BUF_SIZE,
                                   NULL)) >= 0) {
        const int channel_count = op_head(self->opus_file, -1)->channel_count;
        aa_int *channels = self->channels;
        int c;

        channels->reset(channels);

        /*split buffer by channel*/
        for (c = 0; c < channel_count; c++) {
            a_int *channel = channels->append(channels);
            int i;

            channel->resize(channel, pcm_frames_read);
            for (i = 0; i < pcm_frames_read; i++) {
                a_append(channel, pcm[c + (i * channel_count)]);
            }
        }

        /*reorder channels to .wav order if necessary*/
        switch (channel_count) {
        case 1:
        case 2:
        default:
            /*no change*/
            break;
        case 3:
            /*fL fC fR -> fL fR fC*/
            a_int_swap(channels->_[1], channels->_[2]);
            break;
        case 4:
            /*fL fR bL bR -> fL fR bL bR*/
            /*no change*/
            break;
        case 5:
            /*fL fC fR bL bR -> fL fR fC bL bR*/
            a_int_swap(channels->_[1], channels->_[2]);
            break;
        case 6:
            /*fL fC fR bL bR LFE -> fL fR fC bL bR LFE*/
            a_int_swap(channels->_[1], channels->_[2]);

            /*fL fR fC bL bR LFE -> fL fR fC LFE bR bL*/
            a_int_swap(channels->_[3], channels->_[5]);

            /*fL fR fC LFE bR bL -> fL fR fC LFE bL bR*/
            a_int_swap(channels->_[4], channels->_[5]);
            break;
        case 7:
            /*fL fC fR sL sR bC LFE -> fL fR fC sL sR bC LFE*/
            a_int_swap(channels->_[1], channels->_[2]);

            /*fL fR fC sL sR bC LFE -> fL fR fC LFE sR bC sL*/
            a_int_swap(channels->_[3], channels->_[6]);

            /*fL fR fC LFE sR bC sL -> fL fR fC LFE bC sR sL*/
            a_int_swap(channels->_[4], channels->_[5]);

            /*fL fR fC LFE bC sR sL -> fL fR fC LFE bC sL sR*/
            a_int_swap(channels->_[5], channels->_[6]);
            break;
        case 8:
            /*fL fC fR sL sR bL bR LFE -> fL fR fC sL sR bL bR LFE*/
            a_int_swap(channels->_[1], channels->_[2]);

            /*fL fR fC sL sR bL bR LFE -> fL fR fC LFE sR bL bR sL*/
            a_int_swap(channels->_[3], channels->_[6]);

            /*fL fR fC LFE sR bL bR sL -> fL fR fC LFE bL sR bR sL*/
            a_int_swap(channels->_[4], channels->_[5]);

            /*fL fR fC LFE bL sR bR sL -> fL fR fC LFE bL bR sR sL*/
            a_int_swap(channels->_[5], channels->_[6]);

            /*fL fR fC LFE bL bR sR sL -> fL fR fC LFE bL bR sL sR*/
            a_int_swap(channels->_[6], channels->_[7]);
            break;
        }

        /*return new FrameList object*/
        return aa_int_to_FrameList(self->audiotools_pcm,
                                   channels,
                                   16);
    } else {
        /*some sort of read error occurred*/
        PyErr_SetString(PyExc_ValueError, "error reading from file");
        return NULL;
    }
}