I'll post the whole code below. What you suggested did not work.
public int m4aToBassStream(string m4aFilePath, int channels, bool doDecode)
{
var opusData = ExtractOpusDataFromMP4(m4aFilePath);
if (opusData.Count() == 0) return 0;
opusSamples = opusData.ToArray();
channelCount = channels;
return FortniteFestivalToBassStream(doDecode);
}
private static List<byte> ExtractOpusDataFromMP4(string m4aFilePath)
{
List<byte> opusData = new List<byte>();
opusPackets = new List<byte[]>();
.....extract mp4 data containing opus packets......
return opusData;
}
private static int FortniteFestivalToBassStream(bool doDecode)
{
try
{
BASS_OPUS_HEAD head = new BASS_OPUS_HEAD
{
version = 1,
channels = (byte)channelCount,
preskip = 312,
inputrate = 48000,
gain = 0,
mapping = channelCount == 2 ? (byte)0 : (byte)255,
streams = (byte)(channelCount / 2),
coupled = (byte)(channelCount / 2),
chanmap = new byte[] { }
};
head.chanmap = new byte[255];
for (int i = 0; i < head.channels; i++)
{
head.chanmap[i] = (byte)i;
}
int flags = doDecode ? (int)(BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT) : (int)BASSFlag.BASS_SAMPLE_FLOAT;
int streamHandle = BASS_OPUS_StreamCreate(ref head, (uint)flags, STREAMPROC_PUSH, IntPtr.Zero);
if (streamHandle == 0)
{
MessageBox.Show("Failed to create Opus stream. Error: " + Bass.BASS_ErrorGetCode());
return 0;
}
PushOpusPacketsToStream(streamHandle);
return streamHandle;
}
catch (Exception e)
{
MessageBox.Show("Error creating stream handle: " + e.Message + "\nBASS says: " + Bass.BASS_ErrorGetCode());
return 0;
}
}
private static void PushOpusPacketsToStream(int streamHandle)
{
GCHandle handle = GCHandle.Alloc(opusSamples, GCHandleType.Pinned);
try
{
IntPtr pointer = handle.AddrOfPinnedObject();
int offset = 0;
int packetCount = 0;
int totalBytesPushed = 0;
while (offset < opusSamples.Length)
{
// Check for size identifier
if (offset + 4 > opusSamples.Length)
{
MessageBox.Show("Not enough data for size identifier.");
break;
}
int packetSize = BitConverter.ToInt32(opusSamples, offset);
offset += 4;
if (packetSize <= 0 || offset + packetSize > opusSamples.Length)
{
MessageBox.Show("Invalid or incomplete packet data.");
break;
}
int result = BASS_OPUS_StreamPutData(streamHandle, IntPtr.Add(pointer, offset), packetSize);
if (result == -1)
{
MessageBox.Show("Failed to push data. Error: " + Bass.BASS_ErrorGetCode());
break;
}
offset += packetSize;
totalBytesPushed += packetSize;
packetCount++;
//MessageBox.Show($"Pushed packet {packetCount}: {packetSize} bytes");
}
//MessageBox.Show($"Total bytes pushed: {totalBytesPushed}");
//MessageBox.Show($"Total packets processed: {packetCount}");
// Signal end of stream
BASS_OPUS_StreamPutData(streamHandle, IntPtr.Zero, (int)BASSStreamProc.BASS_STREAMPROC_END);
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
finally
{
handle.Free();
}
}
this all works for writing the opus data to file, but not to play the channel containing the opus data. even if I don't use the decode flag.
BassStream = fnfParser.m4aToBassStream(m4aFilePath, 10, false);//always 10 channels, no preview allowed here
if (BassStream == 0)
{
MessageBox.Show("File '" + m4aFilePath + "' is not a valid input file", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
whether with decode or not, BassStream has a valid result, not 0.
BassEnc_Opus.BASS_Encode_OPUS_StartFile(fnfStream, "--vbr --music", BASSEncode.BASS_ENCODE_DEFAULT | BASSEncode.BASS_ENCODE_AUTOFREE, tempFile);
while (true)
{
var buffer = new byte[20000];
var c = Bass.BASS_ChannelGetData(fnfStream, buffer, buffer.Length);
if (c <= 0) break;
}
Bass.BASS_StreamFree(fnfStream);
BassStream = BassOpus.BASS_OPUS_StreamCreateFile(tempFile, 0L, File.ReadAllBytes(tempFile).Length, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT);
if (BassStream == 0)
{
MessageBox.Show("That is not a valid .m4a input file", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
File.Delete(tempFile);
return;
}
this writes an opus file to hard drive just fine. but then I'm writing out to then read back in.
skipping the code above and and not using the decode flag:
var channel_info = Bass.BASS_ChannelGetInfo(BassStream);
results in a null channel_info.
var len = Bass.BASS_ChannelGetLength(BassStream);
results in a -1 length.
I don't know why this is happening. Is it a byproduct of it taking in raw opus data? Or something I'm missing about how BASS works internally?