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; }
/* * 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; }
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; }
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; }
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; }
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); }
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; } }
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; }
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; }
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; }
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(); } } } }
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; }
/*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; } }