I am using Winforms and WindowsMediaPlayer to create a music player. In the form I have a pictureBox with a waveform rendered by NAudio which is saved to an image and loaded upon song change.
when mouseDown the song currentPosition changes to the mouse position over the waveform image.
With mp3 it works very accurate but when I play a flac file the position is very inaccurate.
(the waveform image for mp3 and flac is identical)
Should it have something to do with bitrate?
mp3 = 256 Kbps - Length = 07:44
flac = 892 Kbps - Length = 07:44
f.i.:
flac (x) | mp3 (y)
[ x and y represent mouse position and current song position to be at same real song position (what you hear) ]
somewhere in the beginning:
mousePosition: (x)30 | (y)44
currentSongPosition: (x)109 | (y)159
near the end:
mousePosition: (x)453 | (y)450
currentSongPosition: (x)1623 | (y)1607
This is my mouseDownEvent:
private void pbWaveForm_MouseDown(object sender, MouseEventArgs e)
{
double timePos = 0;
pnlWaveScrub.Height = pbWaveForm.Height;
double MousePosition = e.X;
double dur = musicPlayer.currentMedia.duration;
double ratio = MousePosition / (pbWaveForm.Width );
timePos = ratio * dur;
musicPlayer.controls.currentPosition = (int)timePos;
//MessageBox.Show(Convert.ToString((int)timePos) + " " + MousePosition.ToString());
}
I am planning an if statement with:
FileInfo f = new FileInfo()
if (f.Extention.Equals(".flac"))
{
// code to calculate different timePos
timePos = differentTimepos
musicPlayer.controls.currentPosition = (int)timePos;
}
If anyone can improve my code I would be delighted with it, thanks!
Related
I'm using node.js for a project im doing.
The project is to convert words into numbers and then to take those numbers and create an audio output.
The audio output should play the numbers as frequencies. for example, I have an array of numbers [913, 250,352] now I want to play those numbers as frequencies.
I know I can play them in the browser with audio API or any other third package that allows me to do so.
The thing is that I want to create some audio file, I tried to convert those numbers into notes and then save it as Midi file, I succeed but the problem is that the midi file takes the frequencies, convert them into the closest note (example: 913 will convert into 932.33HZ - which is note number 81),
// add a track
var array = gematriaArray
var count = 0
var track = midi.addTrack()
var note
for (var i = 0; i < array.length; i++) {
note = array[i]
track = track.addNote({
//here im converting the freq -> midi note.
midi: ftom(parseInt(note)),
time: count,
duration: 3
})
count++
}
// write the output
fs.writeFileSync('./public/sounds/' + name + random + '.mid', new Buffer.from(midi.toArray()))
I searched the internet but I couldn't find anything that can help.
I really want to have a file that the user can download with those numbers as frequencies, someone knows what can be done to get this result?
Thanks in advance for the helpers.
this function will populate a buffer with floating point values which represent the height of the raw audio curve for the given frequency
var pop_audio_buffer_custom = function (number_of_samples, given_freq, samples_per_second) {
var number_of_samples = Math.round(number_of_samples);
var audio_obj = {};
var source_buffer = new Float32Array(number_of_samples);
audio_obj.buffer = source_buffer;
var incr_theta = (2.0 * Math.PI * given_freq) / samples_per_second;
var theta = 0.0;
for (var curr_sample = 0; curr_sample < number_of_samples; curr_sample++) {
audio_obj.buffer[curr_sample] = Math.sin(theta);
console.log(audio_obj.buffer[curr_sample] , "theta ", theta);
theta += incr_theta;
}
return audio_obj;
}; // pop_audio_buffer_custom
var number_of_samples = 10000; // long enough to be audible
var given_freq = 300;
var samples_per_second = 44100; // CD quality sample rate
var wav_output_filename = "/tmp/wav_output_filename.wav"
var synthesized_obj = {};
synthesized_obj.buffer = pop_audio_buffer_custom(number_of_samples, given_freq, samples_per_second);
the world of digital audio is non trivial ... the next step once you have an audio buffer is to translate the floating point representation into something which can be stored in bytes ( typically 16 bit integers dependent on your choice of bit depth ) ... then that 16 bit integer buffer needs to get written out as a WAV file
audio is a wave sometimes called a time series ... when you pound your fist onto the table the table wobbles up and down which pushes tiny air molecules in unison with that wobble ... this wobbling of air propagates across the room and reaches a microphone diaphragm or maybe your eardrum which in turn wobbles in resonance with this wave ... if you glued a pencil onto the diaphragm so it wobbled along with the diaphragm and you slowly slid a strip of paper along the lead tip of the pencil you would see a curve being written onto that paper strip ... this is the audio curve ... an audio sample is just the height of that curve at an instant of time ... if you repeatedly wrote down this curve height value X times per second at a constant rate you will have a list of data points of raw audio ( this is what above function creates ) ... so a given audio sample is simply the value of the audio curve height at a given instant in time ... since computers are not continuous instead are discrete they cannot handle the entire pencil drawn curve so only care about this list of instantaneously measured curve height values ... those are audio samples
above 32 bit floating point buffer can be fed into following function to return a 16 bit integer buffer
var convert_32_bit_float_into_signed_16_bit_int_lossy = function(input_32_bit_buffer) {
// this method is LOSSY - intended as preliminary step when saving audio into WAV format files
// output is a byte array where the 16 bit output format
// is spread across two bytes in little endian ordering
var size_source_buffer = input_32_bit_buffer.length;
var buffer_byte_array = new Int16Array(size_source_buffer * 2); // Int8Array 8-bit twos complement signed integer
var value_16_bit_signed_int;
var index_byte = 0;
console.log("size_source_buffer", size_source_buffer);
for (var index = 0; index < size_source_buffer; index++) {
value_16_bit_signed_int = ~~((0 < input_32_bit_buffer[index]) ? input_32_bit_buffer[index] * 0x7FFF :
input_32_bit_buffer[index] * 0x8000);
buffer_byte_array[index_byte] = value_16_bit_signed_int & 0xFF; // bitwise AND operation to pluck out only the least significant byte
var byte_two_of_two = (value_16_bit_signed_int >> 8); // bit shift down to access the most significant byte
buffer_byte_array[index_byte + 1] = byte_two_of_two;
index_byte += 2;
};
// ---
return buffer_byte_array;
};
next step is to persist above 16 bit int buffer into a wav file ... I suggest you use one of the many nodejs libraries for that ( or even better write your own as its only two pages of code ;-)))
I am trying to extract the depth video from a recording (mkv), but the problem is that its extracted in grayscale b16g format. Is it possible to extract or obtain the depth video with color as viewed in the Azure Kinect Viewer? Camera used is Azure Kinect DK.
Thanks, any feedback is appreciated.
This is the steps I used:
ffmpeg -i output.mkv -map 0:1 -vsync 0 depth%03d.png
this extracts the depth track as a sequence of 16-bit PNGs.
Source: https://learn.microsoft.com/en-us/azure/kinect-dk/record-file-format
then
ffmpeg -r 30 -i depth%03d.png -c:v libx264 -vf “fps=30,format=yuv420p” depth.mp4
recreates the depth video from the png images. but the output video is in grayscale.
Source: How to create a video from images with FFmpeg?
The viewer normalizes the depth based on depth modes min and max depth so that the entire 16bit depth range is used. Then it uses the following code to colorize.
static inline BgraPixel ColorizeBlueToRed(const DepthPixel &depthPixel,
const DepthPixel &min,
const DepthPixel &max)
{
constexpr uint8_t PixelMax = std::numeric_limits<uint8_t>::max();
// Default to opaque black.
//
BgraPixel result = { 0, 0, 0, PixelMax };
// If the pixel is actual zero and not just below the min value, make it black
//
if (depthPixel == 0)
{
return result;
}
uint16_t clampedValue = depthPixel;
clampedValue = std::min(clampedValue, max);
clampedValue = std::max(clampedValue, min);
// Normalize to [0, 1]
//
float hue = (clampedValue - min) / static_cast<float>(max - min);
// The 'hue' coordinate in HSV is a polar coordinate, so it 'wraps'.
// Purple starts after blue and is close enough to red to be a bit unclear,
// so we want to go from blue to red. Purple starts around .6666667,
// so we want to normalize to [0, .6666667].
//
constexpr float range = 2.f / 3.f;
hue *= range;
// We want blue to be close and red to be far, so we need to reflect the
// hue across the middle of the range.
//
hue = range - hue;
float fRed = 0.f;
float fGreen = 0.f;
float fBlue = 0.f;
ImGui::ColorConvertHSVtoRGB(hue, 1.f, 1.f, fRed, fGreen, fBlue);
result.Red = static_cast<uint8_t>(fRed * PixelMax);
result.Green = static_cast<uint8_t>(fGreen * PixelMax);
result.Blue = static_cast<uint8_t>(fBlue * PixelMax);
return result;
}
https://github.com/microsoft/Azure-Kinect-Sensor-SDK/blob/95f1d95f1f335b57a350a80a3a62e98e1ee4258d/tools/k4aviewer/k4adepthpixelcolorizer.h#L35
I am a newbie in Java Sounds. I want to play 2 different frequencies alternatively for 1 second each in a loop for some specified time.
Like, if I have 2 frequencies 440hz and 16000hz and the time period is 10 seconds then for every 'even' second 440hz gets played and for every 'odd' second 16000hz, i.e. 5 seconds each alternatively.
I have learned a few things through some examples and I have also made a program that runs for a single user specified frequency for a time also given by the user with the help of those examples.
I will really appreciate if someone can help me out on this.
Thanks.
I am also attaching that single frequency code for reference.
import java.nio.ByteBuffer;
import java.util.Scanner;
import javax.sound.sampled.*;
public class Audio {
public static void main(String[] args) throws InterruptedException, LineUnavailableException {
final int SAMPLING_RATE = 44100; // Audio sampling rate
final int SAMPLE_SIZE = 2; // Audio sample size in bytes
Scanner in = new Scanner(System.in);
int time = in.nextInt(); //Time specified by user in seconds
SourceDataLine line;
double fFreq = in.nextInt(); // Frequency of sine wave in hz
//Position through the sine wave as a percentage (i.e. 0 to 1 is 0 to 2*PI)
double fCyclePosition = 0;
//Open up audio output, using 44100hz sampling rate, 16 bit samples, mono, and big
// endian byte ordering
AudioFormat format = new AudioFormat(SAMPLING_RATE, 16, 1, true, true);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Line matching " + info + " is not supported.");
throw new LineUnavailableException();
}
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
// Make our buffer size match audio system's buffer
ByteBuffer cBuf = ByteBuffer.allocate(line.getBufferSize());
int ctSamplesTotal = SAMPLING_RATE * time; // Output for roughly user specified time in seconds
//On each pass main loop fills the available free space in the audio buffer
//Main loop creates audio samples for sine wave, runs until we tell the thread to exit
//Each sample is spaced 1/SAMPLING_RATE apart in time
while (ctSamplesTotal > 0) {
double fCycleInc = fFreq / SAMPLING_RATE; // Fraction of cycle between samples
cBuf.clear(); // Discard samples from previous pass
// Figure out how many samples we can add
int ctSamplesThisPass = line.available() / SAMPLE_SIZE;
for (int i = 0; i < ctSamplesThisPass; i++) {
cBuf.putShort((short) (Short.MAX_VALUE * Math.sin(2 * Math.PI * fCyclePosition)));
fCyclePosition += fCycleInc;
if (fCyclePosition > 1) {
fCyclePosition -= 1;
}
}
//Write sine samples to the line buffer. If the audio buffer is full, this will
// block until there is room (we never write more samples than buffer will hold)
line.write(cBuf.array(), 0, cBuf.position());
ctSamplesTotal -= ctSamplesThisPass; // Update total number of samples written
//Wait until the buffer is at least half empty before we add more
while (line.getBufferSize() / 2 < line.available()) {
Thread.sleep(1);
}
}
//Done playing the whole waveform, now wait until the queued samples finish
//playing, then clean up and exit
line.drain();
line.close();
}
}
Your best bet is probably creating Clips as shown in the sample code below.
That said, the MHz range is typically not audible—looks like you have a typo in your question. If it's no typo, you will run into issues with Mr. Nyquist.
Another hint: Nobody uses Hungarian Notation in Java.
import javax.sound.sampled.*;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
public class AlternatingTones {
public static void main(final String[] args) throws LineUnavailableException, InterruptedException {
final Clip clip0 = createOneSecondClip(440f);
final Clip clip1 = createOneSecondClip(16000f);
clip0.addLineListener(event -> {
if (event.getType() == LineEvent.Type.STOP) {
clip1.setFramePosition(0);
clip1.start();
}
});
clip1.addLineListener(event -> {
if (event.getType() == LineEvent.Type.STOP) {
clip0.setFramePosition(0);
clip0.start();
}
});
clip0.start();
// prevent JVM from exiting
Thread.sleep(10000000);
}
private static Clip createOneSecondClip(final float frequency) throws LineUnavailableException {
final Clip clip = AudioSystem.getClip();
final AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100f, 16, 1, 2, 44100, true);
final ByteBuffer buffer = ByteBuffer.allocate(44100 * format.getFrameSize());
final ShortBuffer shortBuffer = buffer.asShortBuffer();
final float cycleInc = frequency / format.getFrameRate();
float cyclePosition = 0f;
while (shortBuffer.hasRemaining()) {
shortBuffer.put((short) (Short.MAX_VALUE * Math.sin(2 * Math.PI * cyclePosition)));
cyclePosition += cycleInc;
if (cyclePosition > 1) {
cyclePosition -= 1;
}
}
clip.open(format, buffer.array(), 0, buffer.capacity());
return clip;
}
}
The method I would use would be to count frames while outputting to a SourceDataLine. When you have written one second's worth of frames, switch frequencies. This will give much better timing accuracy than attempting to fiddle with Clips.
I'm unclear if the code you are showing is something you wrote or copied-and-pasted. If you have a question about how it doesn't work, I'm happy to help if you show what you tried and what errors or exceptions were generated.
When outputting to a SourceDataLine, there will have to be a step where you convert the short value (-32768..+32767) to two bytes as per the 16-bit encoding specified in the audio format you have. I don't see where this is being done in your code. [EDIT: can see where the putShort() method does this, though it only works for BigEndian, not the more common LittleEndian.]
Have you looked over the Java Tutorial
Sound Trail?
I'm writing audio from an external decoding library on OS X to an AIFF file, and I am able to swap the endianness of the data with OSSwapInt32().
The resulting AIFF file (16-bit PCM stereo) does play, but the left and right channels are swapped.
Would there be any way to swap the channels as I am writing each buffer?
Here is the relevant loop:
do
{
xmp_get_frame_info(writer_context, &writer_info);
if (writer_info.loop_count > 0)
break;
writeModBuffer.mBuffers[0].mDataByteSize = writer_info.buffer_size;
writeModBuffer.mBuffers[0].mNumberChannels = inputFormat.mChannelsPerFrame;
// Set up our buffer to do the endianness swap
void *new_buffer;
new_buffer = malloc((writer_info.buffer_size) * inputFormat.mBytesPerFrame);
int *ourBuffer = writer_info.buffer;
int *ourNewBuffer = new_buffer;
memset(new_buffer, 0, writer_info.buffer_size);
int i;
for (i = 0; i <= writer_info.buffer_size; i++)
{
ourNewBuffer[i] = OSSwapInt32(ourBuffer[i]);
};
writeModBuffer.mBuffers[0].mData = ourNewBuffer;
frame_size = writer_info.buffer_size / inputFormat.mBytesPerFrame;
err = ExtAudioFileWrite(writeModRef, frame_size, &writeModBuffer);
} while (xmp_play_frame(writer_context) == 0);
This solution is very specific to 2 channel audio. I chose to do it at the same time you're looping to change the byte ordering to avoid an extra loop. I'm going through the loop 1/2 the number and processing two samples per iteration. The samples are interleaved so I copy from odd sample indexes into even sample indexes and vis-a-versa.
for (i = 0; i <= writer_info.buffer_size/2; i++)
{
ourNewBuffer[i*2] = OSSwapInt32(ourBuffer[i*2 + 1]);
ourNewBuffer[i*2 + 1] = OSSwapInt32(ourBuffer[i*2]);
};
An alternative is to use a table lookup for channel mapping.
Is it possible to detect the audio levels from a playing track using background agent or any other way?
What I'm trying to achieve is listen to the track, get a float and change colour based on the levels of the audio being played.
How would you approach?
You need to detect the decibels level of a sound recorded. Actually, in WP7 (I can't find for WP8, yet!) there is no APIs to get decibel level directly. But I can use microphone to get data to simulate decibel. The code like this:
......
microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
........
void microphone_BufferReady(object sender, EventArgs e)
{
double sum = 0;
for (var i = 0; i < buffer.Length; i = i + 2)
{
double sample = BitConverter.ToInt16(buffer, i) / 32768.0;
sum += (sample * sample);
}
double rms = Math.Sqrt(sum / buffer.Length);
decibel = 92.8 + 20 * Math.Log10(rms);
}
This is the source http://social.msdn.microsoft.com/Forums/windowsapps/en-US/f04e0629-2609-4542-a141-46166f4cbdeb/how-to-get-the-decibel-with-c