Can I somehow record and output to WAV with trackPosition, offset. it works fine when played in browser works fine I just wanna output is to WAV file.
for (var i = 0; i <= loop; ++i) {
node = that.context.createBufferSource();
that.nodes.push(node);
node.buffer = clip.get('buffer');
node.connect(gainNode);
// clip offset and duration times
if (loop > 0) {
if (i === 0) { // first subclip
offset = startTime;
duration = duration - offset;
} else if (i === loop) { // last subclip
offset = 0;
duration = endTime;
} else {
offset = 0;
duration = clip.get('buffer').duration;
}
} else { // loop === 0
offset = startTime;
if (inClipStart)
duration = endTime - startTime;
else
duration = clip.clipLength();
}
// sets the clip's playback start time
node.start(
currentTime + trackPosition - cursor,
offset,
duration
);
trackPosition += duration;
}
Check out https://github.com/mattdiamond/Recorderjs - it let's you record/save the output of your Web Audio app as a .wav, which sound like what you're looking for!
Related
How to change sampling rate from 48000 (ue4 default) to 16000 samples and stereo to mono in a wav recording in ue4? I have searched in BPs but not lack. The image below shows what I have done with BPs. In order for this to work I had to change in WindowsEngine.ini the audio settings to XAudio (see this: https://www.youtube.com/watch?v=BpP1SxxwYIE)
Therefore I assume that this should be only possible with C++.
I did it with C++
File -> New C++ class -> VoiceCharacter -> Public
Change your character to have "VoiceCharacter" as parent. It can be found in Class settings of your character BP.
Add this method to VoiceCharacter C++ class and built and play.
void AVoiceCharacter::StereoToMono(TArray<uint8> stereoWavBytes, TArray<uint8>& monoWavBytes)
{
if(stereoWavBytes.Num() == 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "Stereo Bytes is empty");
return;
}
//Change wav headers
for (int i = 0; i < 44; i++)
{
//NumChannels starts from 22 to 24
if (i == 22)
{
short originalChannels = (*(short*)&stereoWavBytes[i]);
short NumChannels = originalChannels / 2;
FString message = FString::FromInt(originalChannels);
GEngine->AddOnScreenDebugMessage(-1, 25.f, FColor::Red, message);
monoWavBytes.Append((uint8*)&NumChannels, sizeof(NumChannels));
i++;
}//SamplingRate starts from 24 to 27
else if (i == 24)
{
int OriginalSamplingRate = (*(int*)&stereoWavBytes[i]);
int SamplingRate = OriginalSamplingRate / 3 ;
GEngine->AddOnScreenDebugMessage(-1, 25.f, FColor::Yellow, FString::FromInt(OriginalSamplingRate));
monoWavBytes.Append((uint8*)&SamplingRate, sizeof(SamplingRate));
i += 3;
} //ByteRate starts from 28 to 32
else if (i == 28)
{
int OriginalByteRate = (*(int*)&stereoWavBytes[i]);
int ByteRate = OriginalByteRate / 6 ;
GEngine->AddOnScreenDebugMessage(-1, 25.f, FColor::Yellow, FString::FromInt(OriginalByteRate));
monoWavBytes.Append((uint8*)&ByteRate, sizeof(ByteRate));
i += 3;
}
//BlockAlign starts from 32 to 34
else if (i == 32)
{
short BlockAlign = (*(short*)&stereoWavBytes[i]) / 2;
GEngine->AddOnScreenDebugMessage(-1, 25.f, FColor::White, FString::FromInt(BlockAlign));
monoWavBytes.Append((uint8*)&BlockAlign, sizeof(BlockAlign));
i++;
}
//SubChunkSize starts from 40 to 44
else if (i == 40)
{
int SubChunkSize = (*(int*)&stereoWavBytes[i]) / 2;
GEngine->AddOnScreenDebugMessage(-1, 25.f, FColor::Green, FString::FromInt(SubChunkSize));
monoWavBytes.Append((uint8*)&SubChunkSize, sizeof(SubChunkSize));
i += 3;
}
else
{
monoWavBytes.Add(stereoWavBytes[i]);
}
}
//Copies only the left channel and ignores the right channel
// for (int i = 44; i < stereoWavBytes.Num(); i += 4)
// {
// monoWavBytes.Add(stereoWavBytes[i]);
// monoWavBytes.Add(stereoWavBytes[i+1]);
// }
//Copies only the left channel and ignores the right channel. Also downsamples by 3,
// i.e. converts Windows 48000 sampling rate of ue4 to 16000
for (int i = 44; i < stereoWavBytes.Num(); i += 12)
{
monoWavBytes.Add(stereoWavBytes[i]);
monoWavBytes.Add(stereoWavBytes[i+1]);
}
}
Do not forget to add this in VoiceCharacter.h so that you can use it BPs.
UFUNCTION(BlueprintCallable, Category="Audio")
static void StereoToMono(TArray<uint8> stereoWavBytes, TArray<uint8>& monoWavBytes);
and here is how use it in BPs
Some useful plugins for (CUFile)
https://github.com/getnamo/nodejs-ue4
https://github.com/getnamo/socketio-client-ue4
I have started a game and I want a stopwatch (countup timer) in it I have found a code to activate it. But how to stop it?
Source: https://docs.idew.org/video-game/project-references/phaser-coding/timers#create-count-up-timer
Code related to the stopwatch:
//global vars
var timeText; var min, sec;
function create timeText = game.add.text(600, 20, "", { fontSize: '20px', fill: '#FFF' }); timeText.fixedToCamera = true;
function displayTimeElapsed(){
if (knight.x >= 96){
var time = Math.floor(game.time.totalElapsedSeconds() );
min = Math.floor(time / 60);
sec = time % 60;
if (min < 10) {
min = "0" + min;
}
if (sec < 10) {
sec = "0" + sec;
}
timeText.text = "Time: " + min + ":" + sec;
}
}
//update displayTimeElapsed();
you could add a boolean pause that if true it will set the time to what the remaining time is and when false keep doing what is doing.
it would be easier to explain it if you show your code. I will update my answer accordingly.
Lets create it from scratch,
first of all in your create() function, lets add a text to display the timer on the screen:
// CREATE()
this.timerText = this.add.text(x, y, "").setColor("#000000");
Second lets create a function, bellow the update(), to count down :
showTimer(){
// Assuming you want 60 seconds, if not just chenge the 60's for whatever time you want
let maxTime = 60;
let time = Math.floor(this.time.totalElapsedSeconds() );
let sec = time % 60;
timeText.setText(sec); // Adding the timer to our text
}
Third, create a variable in the create() to track when the timer ends:
// CREATE()
this.timerOver = false;
// And lets start the timer
this.timer = this.time.delayedCall(60000);
Now lets modify our showTimer() function:
showTimer(){
let maxTime = 60;
let time = Math.floor(this.time.totalElapsedSeconds() );
let timeLeft = maxTime - time; // Check how much time is left
// When the countdown is over
if(timeLeft <= 0){
timeLeft = 0;
this.timerOver = true; // Setting our variable to true
}
let sec = time % 60;
timeText.setText(sec);
}
and last, in our update() function lets check if our variable this.timerOver is true
if (this.timerOver === false){
this.showTimer(); // Calling our function every frame
}
else {
// Whatever you want it to do when timer comes to 0
}
I want to understand CPU cache utilisation. For that purpose i wrote a small bit of Node.js code:
let testArray = [];
let length = "";
let times = "";
do {
testArray.push(Math.random());
if (testArray.length % 1000 === 0) {
testArray = testArray.slice();
const start = performance.now();
action(testArray);
const stop = performance.now();
const duration = stop - start;
length += testArray.length + "," + endOfLine;
times += duration + "," + endOfLine;
console.log(`Took: ${duration}, length: ${testArray.length}`);
}
}
while (testArray.length < 10000000)
function action(a) {
let sum = 0;
for (let index = 0; index < 10000; index++) {
sum += a[index];
}
}
I would expect the duration of the call to the function to be similar to this chart:
In spite of my expectations the durations are pretty much the same no matter what the size of the array is. I thought that as the array gets bigger it would exceed L1, L2 and L3 caches and I would see it on the graph.
Is my code wrong or am I missing something?
I've been banging my head against a wall on this for two days now, and I really hope someone can help on this.
I've taken some code for a getUserMedia microphone recorder from https://higuma.github.io/wav-audio-encoder-js/ + https://github.com/higuma/wav-audio-encoder-js here. I've stripped out the components I don't need - and somehow, in the process, I've managed to make it so that there is no audio coming through on the generated file.
It looks like it formats correctly - but is completely silent. I'm getting 0 errors to work from.
// navigator.getUserMedia shim
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
// URL shim
window.URL = window.URL || window.webkitURL;
// audio context + .createScriptProcessor shim
var audioContext = new AudioContext;
if (audioContext.createScriptProcessor == null) {
audioContext.createScriptProcessor = audioContext.createJavaScriptNode;
}
// selectors
var $microphone = $('#microphone');
var $cancel = $('#cancel');
var $recordingList = $('#recording-list');
var $timeDisplay = $('#time-display');
var $microphoneLevel = $('#microphone-level');
var microphone = undefined;
var input = audioContext.createGain();
var mixer = audioContext.createGain();
var microphoneLevel = audioContext.createGain();
microphoneLevel.gain.value = 0;
microphoneLevel.connect(mixer);
var processor = undefined;
var startTime = null;
var encoder = undefined;
// obtaining microphone input
$microphone.click(function() {
navigator.getUserMedia({ audio: true },
function(stream) {
microphone = audioContext.createMediaStreamSource(stream);
microphone.connect(microphoneLevel);
console.log(microphone);
},
function(error) {
window.alert("Could not get audio input");
});
});
// start/stop recording
$microphone.click(function() {
if (startTime != null) {
stopRecording(true);
} else {
startRecording();
}
});
// cancel recording (without saving)
$cancel.click(function() {
stopRecording(false);
});
// microphone level slider
$microphoneLevel.on('input', function() {
var level = $microphoneLevel[0].valueAsNumber / 100;
microphoneLevel.gain.value = level * level;
});
function startRecording() {
startTime = Date.now();
$microphone.html('Stop');
$cancel.removeClass("hidden");
startRecordingProcess();
}
function startRecordingProcess() {
processor = audioContext.createScriptProcessor(1024, 2, 2);
input.connect(processor);
processor.connect(audioContext.destination);
// wav encoder
encoder = new WavAudioEncoder(audioContext.sampleRate, 2);
processor.onaudioprocess = function(event) {
encoder.encode(getBuffers(event));
};
}
function getBuffers(event) {
var buffers = [];
for (var ch = 0; ch < 2; ++ch) {
buffers[ch] = event.inputBuffer.getChannelData(ch);
}
return buffers;
}
function stopRecording(finish) {
startTime = null;
$timeDisplay.html('00:00');
$microphone.html('<i class="start fa fa-microphone fa-5x" aria-hidden="true"></i>');
$cancel.addClass('hidden');
stopRecordingProcess(finish);
}
function stopRecordingProcess(finish) {
input.disconnect();
processor.disconnect();
if (finish) { // if microphone pressed
saveRecording(encoder.finish());
} else { // if cancel pressed
encoder.cancel();
}
}
function saveRecording(blob) {
var url = URL.createObjectURL(blob);
var html = "<p class='recording' recording='" + url + "'><a class='btn btn-default' href='" + url + "' download='recording.wav'>Save Recording</a></p>";
$recordingList.prepend($(html));
// once we have done all the processing, upload the file to beyond verbal
// uploadFile(blob);
}
// update the recording timer
function minuteSeconds(n) { return (n < 10 ? "0" : "") + n; }
function updateDateTime() {
if (startTime !== null) {
var sec = Math.floor((Date.now() - startTime) / 1000);
$timeDisplay.html(minuteSeconds(sec / 60 | 0) + ":" + minuteSeconds(sec % 60));
}
}
window.setInterval(updateDateTime, 200);
If anyone has run into this before, I'd be really appreciative of a fix.
Thank you all for your time, and have a nice day/night
First check your microphone with general recording demo.
If its working you can try passing only Audio Stream & required mime type to media recorder for basic audio recording.
If you want to play with this webaudio context,
Am suspecting issue with microphoneLevel.gain.value = 0;
change it to microphoneLevel.gain.value = 1; //or 2
gain = 0 means we are muting the audio.
gain = 1 default audio level
gain = 0.1 - 0.9 is reducing volume level
gain = above 1.1 increasing the volume level
print the level values in console on
// microphone level slider
$microphoneLevel.on('input', function() {
var level = $microphoneLevel[0].valueAsNumber / 100;
console.log('value: ' + $microphoneLevel[0].valueAsNumber + ' Level: ' + level);
microphoneLevel.gain.value = level * level; // if level is zero, then its silent
// its better if you have a predefined level values based slider position instead of multiplying it
});
See my demo and source
I am trying to figure out how to use "sound off" and "sound on" images to control game sound. The code below displays a sound button but when you click on it, it mutes the sounds but adds a shaded circle over the button.
I would like some guide or how to make it switch from a sound on to a sound off image button as I am new to Unity.
Image File Names: SoundButton.psd and WhiteCircle.psd
var whiteCircle : GameObject;
var numberOfTouch : int = 0;
private var a : float = 1;
function Start() {
if (PlayerPrefs.GetInt("SoundBoolean") == 0) {
//check whether the sound is included, if turned on, then play sound.
numberOfTouch = 0;
whiteCircle.GetComponent(SpriteRenderer).enabled = false;
}
if (PlayerPrefs.GetInt("SoundBoolean") == 1) {
//check whether the sound is included, if turned off, then turn off the sound.
numberOfTouch = 1;
whiteCircle.GetComponent(SpriteRenderer).enabled = true;
}
}
function OnMouseDown () {
if (a <= 0) {
if (numberOfTouch == 0) {
//completely turn off the music.
a = 1;
numberOfTouch = 1;
gameObject.GetComponent.<AudioSource>().Play();
whiteCircle.GetComponent(SpriteRenderer).enabled = true;
PlayerPrefs.SetInt("SoundBoolean", 1);
PlayerPrefs.Save();
}
}
if (a <= 0) {
if (numberOfTouch == 1) {
//a fully turn on the music.
a = 1;
numberOfTouch = 0;
whiteCircle.GetComponent(SpriteRenderer).enabled = false;
PlayerPrefs.SetInt("SoundBoolean", 0);
PlayerPrefs.Save();
}
}
}
function Update() {
if (a >= 0) {
a -= 0.1;
}
}
As I understood correctly, you're looking for something to change the sprite on an object you have. I'm not testing my code or anything, but perhaps it can help you solve your problem.
var sprite1 : Sprite; // Drag your first sprite here
var sprite2 : Sprite; // Drag your second sprite here
var spriteRenderer : SpriteRenderer = whiteCircle.GetComponent(SpriteRenderer);
var whiteCircle : GameObject;
var numberOfTouch : int = 0;
private var a : float = 1;
function Start() {
if (PlayerPrefs.GetInt("SoundBoolean") == 0) {
//check whether the sound is included, if turned on, then play sound.
numberOfTouch = 0;
spriteRenderer.sprite = sprite2;
}
if (PlayerPrefs.GetInt("SoundBoolean") == 1) {
//check whether the sound is included, if turned off, then turn off the sound.
numberOfTouch = 1;
spriteRenderer.sprite = sprite1;
}
}
function OnMouseDown () {
if (a <= 0) {
if (numberOfTouch == 0) {
//completely turn off the music.
a = 1;
numberOfTouch = 1;
gameObject.GetComponent.<AudioSource>().Play();
spriteRenderer.sprite = sprite1;
PlayerPrefs.SetInt("SoundBoolean", 1);
PlayerPrefs.Save();
}
}
if (a <= 0) {
if (numberOfTouch == 1) {
//a fully turn on the music.
a = 1;
numberOfTouch = 0;
spriteRenderer.sprite = sprite2;
PlayerPrefs.SetInt("SoundBoolean", 0);
PlayerPrefs.Save();
}
}
}
function Update() {
if (a >= 0) {
a -= 0.1;
}
}
Basically, add two sprite points to where you can drag your image files, then replace the sprite on a certain spriterenderer (instead of turning it on and off).