I'm trying to complete an assignment that requires me to make a music player using the MSP430 microprocessor and Launchpad kit. I have the player completely working, but for some reason when I try to play above a certain note, it outputs rapid clicking instead of the tone.
I know the speaker can produce a higher tone, so I am fairly certain it's an issue with my software, probably creating some sort of math error. Here is my code (at least the part that handles the notes):
asm(" .length 10000");
asm(" .width 132");
#include "msp430g2553.h"
//-----------------------
// define the bit mask (within P1) corresponding to output TA0
#define TA0_BIT 0x02
// define the port and location for the button (this is the built in button)
// specific bit for the button
#define BUTTON_BIT 0x04
#define PLUS_BUTTON 0x08 //Defines the "GO FASTER" button to P1.3
#define MINUS_BUTTON 0x10 //Defines the "SLOW DOWN" button to P1.4
#define SHIFT 0x20
//----------------------------------
// Some global variables (mainly to look at in the debugger)
volatile unsigned halfPeriod; // half period count for the timer
volatile unsigned long intcount=0; // number of times the interrupt has occurred
volatile unsigned soundOn=0; // state of sound: 0 or OUTMOD_4 (0x0080)
volatile int noteCount = 0;
volatile int noteLength = 0;
volatile int deltaHP=1; // step in half period per half period
volatile unsigned int plus_on;
volatile unsigned int minus_on;
volatile double speed = 1;
volatile int shiftkey = 0;
static const int noteArray[] = {800, 1000, 900, 800}; //THESE ARE THE NOTES
static const int noteLengths[] = {200, 500, 500, 500};
void init_timer(void); // routine to setup the timer
void init_button(void); // routine to setup the button
// ++++++++++++++++++++++++++
void main(){
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_1MHZ; // 1Mhz calibration for clock
DCOCTL = CALDCO_1MHZ;
//halfPeriod=noteArray[0]; // initial half-period at lowest frequency
init_timer(); // initialize timer
init_button(); // initialize the button
_bis_SR_register(GIE+LPM0_bits);// enable general interrupts and power down CPU
}
// +++++++++++++++++++++++++++
// Sound Production System
void init_timer(){ // initialization and start of timer
TA0CTL |=TACLR; // reset clock
TA0CTL =TASSEL1+ID_0+MC_2; // clock source = SMCLK, clock divider=1, continuous mode,
TA0CCTL0=soundOn+CCIE; // compare mode, outmod=sound, interrupt CCR1 on
TA0CCR0 = TAR+noteArray[0]; // time for first alarm
P1SEL|=TA0_BIT; // connect timer output to pin
P1DIR|=TA0_BIT;
}
// +++++++++++++++++++++++++++
void interrupt sound_handler(){
TACCR0 += (noteArray[noteCount]); // advance 'alarm' time
if (soundOn){ // change half period if the sound is playing
noteLength++;
if (noteLength >= (speed* noteLengths[noteCount])) {
noteLength=0;
noteCount++;
if (noteCount == sizeof(noteArray)/sizeof(int)) {
//halfPeriod += deltaHP;
noteCount = 0;
//deltaHP=-deltaHP;
}
}
}
TA0CCTL0 = CCIE + soundOn; // update control register with current soundOn
++intcount; // advance debug counter
}
ISR_VECTOR(sound_handler,".int09") // declare interrupt vector
Currently I have just 4 random notes in there with 4 random lengths to demonstrate the error. The strange clicking noise happens somewhere between a note value of 800 and 900. Am I just missing something in my code that would produce an error for a number smaller than 8xx? I don't see any spots for division errors or the like but I could be wrong.
Thank you.
ALSO: I should note that when the error occurs, the clicking lasts a very long time, much longer than the corresponding length for that note, but it isn't permanent. Eventually the player moves on to the next note and plays it normally as long as it's larger than 900 or so.
If the interrupt handler does not execute fast enough, the setting of the next event (TACCR0 += noteArray[...]) will come too late, i.e., after that timer value has already been reached. So the next timer interrupt will fire not after 800 ticks but after 216+800 ticks.
You might try to optimize the interrup handler function.
In particular, floating-point emulation can take hundreds of cycles; remove speed.
However, instead of toggling the output in software, you should take advantage of the hardware capabilites, and generate the waveform with the PWM function: run the timer in Up mode, and use set/reset output mode for the second CCR (see section 12.2.5.2 of the User's Guide).
(This implies that you need timer interrupts only to start/stop notes, so to fit into the 216 limit, you probably want to use a second timer based on a much slower clock.)
Related
Hey guys so just as a disclaimer I'm relatively new to programming so if I'm making some super obvious mistake please go easy on me
So I'm trying to create a higher customizable Countdown timer for my game, and I want it to be able to be accurate to 0.01 Seconds. I decided I would use the Coroutine method for creating my timer instead of the delta-time one I have seen a couple of times, thinking that this would be a more efficient approach. My game is not very intensive and thus easily runs on hundreds of frames per second, so I thought that using Waitforseconds(0.01) is going to work better because it only needs to be called 100 times every second rather than multiple hundreds. however, I have come into a major issue with my timer. It is EXTREMELY slow. I ran the countdown timer on google and mine side by side starting at 25 seconds and it beat mine out by ten seconds. I even tried adding a artifical delay thinking the waitforseconds function was overshooting, so I would have the time tick down 0.01 seconds when a bit less then that had passed, but my results ended up being sort of inconsistent. Here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TimerScript : MonoBehaviour
{
public Text textDisplay;
private double secondsLeft = 30;
public bool takingAway = false;
private string Texttodisplay;
public int Milisecondsdigits = 2;
void Start()
{
textDisplay = GetComponent<Text>();
Texttodisplay = "00:" + secondsLeft;
if(Milisecondsdigits == 0)
{
Milisecondsdigits = -1;
}
}
void Update()
{
if (takingAway == false && secondsLeft > 0)
{
StopAllCoroutines();
StartCoroutine(TimerTake());
}
if(Texttodisplay.Length > 8 - (Mathf.Abs(Milisecondsdigits -2)))
{
Texttodisplay = Texttodisplay.Substring(0,8- (Mathf.Abs(Milisecondsdigits -2)));
}
textDisplay.text = Texttodisplay;
}
IEnumerator TimerTake()
{
takingAway = true;
yield return new WaitForSeconds(0.01f);
secondsLeft -= 0.01;
if(secondsLeft < 10)
{
Texttodisplay = "00:0" + secondsLeft;
}
else
{
Texttodisplay = "00:" + secondsLeft;
}
takingAway = false;
}
}
could somebody please let me know how I could cause this to become more accurate or why it's acting extremely inaccurate currently :/
Coroutine events like WaitForSeconds trigger at a defined point in Unity's event cycle, which takes place after Update() is processed (see
https://docs.unity3d.com/Manual/ExecutionOrder.html). This defined execution point might not line up exactly with the timer delay. This means it may wait longer than you want it to.
In your example, you tell it to wait for 0.01 seconds. Let's say that you are running a game at 30 frames per second. The frame time for 30 frames per second is 1/30 seconds, or approximately 0.0333 seconds. WaitForSeconds will then wait for the next frame, and 0.0333 seconds passes until the next frame. Then the next WaitForSeconds event cycle, it sees that the delay has passed and triggers, but you actually waited over 3 times as long as you wanted to because of the delay between event cycles. Since your code assumes that WaitForSeconds had only waited for 0.01 seconds, you will end up waiting longer than you intended to. This normally doesn't matter in a lot of applications, but when accumulating with frequent short delays it certainly does.
To solve this, you have two choices:
Accumulate time manually using Time.deltaTime in Update().
Coroutines likely check their completion status per frame in a
similar way in the yield WaitForSeconds event. If coroutines
check if they need to continue every frame, doing this manually with
Time.deltaTime might not be any less efficient at all than a
coroutine. You will have to benchmark to find out, because coroutines being more efficient isn't a safe assumption.
Use Time.time (or Time.realtimeSinceStartup if you want it unscaled) to measure the actual span of time that elapsed after the WaitForSeconds trigger, and use that as what you subtract from your remaining time.
There is also an additional consideration here that if you want your
text display to update at specific regular intervals, you will want
to dynamically adjust what value you pass into WaitForSeconds to
compensate for its drift.
Do you try to do it without Corroutine in a fixed update? Fixed update refresh every 0.02 seconds by default but you can settup to run in 0.01 seconds in Edit > Settings > Time > Fixed Timestep.
Replace the corroutine with a function in FixedUpdate
There is a link with better explation how works fixedupdate.
FixedUpdate Unity
I have used STM32CubeMX/IDE to generate a USB HID project for the STM32F3DISCOVERY board.
The USB BTABLE register is zero, indicating that the BTABLE is at the start of the Packet Memory Area.
(I zero the whole PMA at program start, to avoid stale values.)
Just before the execution of the __HAL_RCC_USB_CLK_ENABLE macro (in HAL_PCD_MspInit() in usbd_conf.c) the values of the BTABLE (at index zero onwards, in the PMA are:
After that macro is executed, the values are:
The macro expands to:
do { \
volatile uint32_t tmpreg; \
((((RCC_TypeDef *) ((0x40000000UL + 0x00020000UL) + 0x00001000UL))->APB1ENR) |= ((0x1UL << (23U))));\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = ((((RCC_TypeDef *) ((0x40000000UL + 0x00020000UL) + 0x00001000UL))->APB1ENR) & ((0x1UL << (23U))));\
(void)tmpreg; \
} while(0U)
How does this macro cause the BTABLE to be initialised?
(I need pma[12] to be 0x100 instead of 0x0 as I want to use endpoint 3 for the HID interface in a composite device. I am using this simple HID device to test the use of a different endpoint. Changing 0x81 to 0x83 in USBD_LL_Init() and #define HID_EPIN_ADDR are not sufficient to change the value of pma[12]. The incorrect TX pointer at pma[12] is used and corrupt data is observed in wireshark.)
Update:
If I add code to manually set pma[12] to 0x100:
HAL_StatusTypeDef HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd,
uint16_t ep_addr,
uint16_t ep_kind,
uint32_t pmaadress)
...
/* Here we check if the endpoint is single or double Buffer*/
if (ep_kind == PCD_SNG_BUF)
{
/* Single Buffer */
ep->doublebuffer = 0U;
/* Configure the PMA */
ep->pmaadress = (uint16_t)pmaadress;
// correct PMA BTABLE
uint32_t *btable = (uint32_t *) USB_PMAADDR; // Test this.
if (ep->is_in) {
btable[ep->num * 4] = pmaadress;
}
}
The value at pam[12] does get set, but it later gets overwritten:
__HAL_RCC_USB_CLK_ENABLE() enables clocks for the USB block. Before it is enabled, all peripheral locations are read as zeroes. After clock is enabled, the actual PMA content becomes visible, whatever was written there before reset or random garbage left after the power up. So executing __HAL_RCC_USB_CLK_ENABLE() has nothing to do with your problem.
I don't know where the TX buffer address for endpoint 3 gets overwritten, but I guess it is the Cube sets it when it decides to send data on the endpoint. I am not familiar with the Cube, does it have an API to send a USB packet?
Also, double-check that your pma array has the right definition. On F1 and I likely F3, there is a 2-byte value at each of the 32-bit location.
UPD: Sorry, I saw this question first, but your real problem is why TX addr gets overwritten or not set up correctly.
I need to collect voice pieces from a continuous audio stream. I need to process later the user's voice piece that has just been said (not for speech recognition). What I am focusing on is only the voice's segmentation based on its loudness.
If after at least 1 second of silence, his voice becomes loud enough for a while, and then silent again for at least 1 second, I say this is a sentence and the voice should be segmented here.
I just know I can get raw audio data from the AudioClip created by Microphone.Start(). I want to write some code like this:
void Start()
{
audio = Microphone.Start(deviceName, true, 10, 16000);
}
void Update()
{
audio.GetData(fdata, 0);
for(int i = 0; i < fdata.Length; i++) {
u16data[i] = Convert.ToUInt16(fdata[i] * 65535);
}
// ... Process u16data
}
But what I'm not sure is:
Every frame when I call audio.GetData(fdata, 0), what I get is the latest 10 seconds of sound data if fdata is big enough or shorter than 10 seconds if fdata is not big enough, is it right?
fdata is a float array, and what I need is a 16 kHz, 16 bit PCM buffer. Is it right to convert the data like: u16data[i] = fdata[i] * 65535?
What is the right way to detect loud moments and silent moments in fdata?
No. you have to read starting at the current position within the AudioClip using Microphone.GetPosition
Get the position in samples of the recording.
and pass the optained index to AudioClip.GetData
Use the offsetSamples parameter to start the read from a specific position in the clip
fdata = new float[clip.samples * clip.channels];
var currentIndex = Microphone.GetPosition(null);
audio.GetData(fdata, currentIndex);
I don't understand what exactly you convert this for. fdata will contain
floats ranging from -1.0f to 1.0f (AudioClip.GetData)
so if for some reason you need to get values between short.MinValue (= -32768) and short.MaxValue(= 32767) than yes you can do that using
u16data[i] = Convert.ToUInt16(fdata[i] * short.MaxValue);
note however that Convert.ToUInt16(float):
value, rounded to the nearest 16-bit unsigned integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.
you might want to rather use Mathf.RoundToInt first to also round up if a value is e.g. 4.5.
u16data[i] = Convert.ToUInt16(Mathf.RoundToInt(fdata[i] * short.MaxValue));
Your naming however suggests that you are actually trying to get unsigned values ushort (or also UInt16). For this you can not have negative values! So you have to shift the float values up in order to map the range (-1.0f | 1.0f ) to the range (0.0f | 1.0f) before multiplaying it by ushort.MaxValue(= 65535)
u16data[i] = Convert.ToUInt16(Mathf.RoundToInt(fdata[i] + 1) / 2 * ushort.MaxValue);
What you receive from AudioClip.GetData are the gain values of the audio track between -1.0f and 1.0f.
so a "loud" moment would be where
Mathf.Abs(fdata[i]) >= aCertainLoudThreshold;
a "silent" moment would be where
Mathf.Abs(fdata[i]) <= aCertainSiltenThreshold;
where aCertainSiltenThreshold might e.g. be 0.2f and aCertainLoudThreshold might e.g. be 0.8f.
I would like to schedule a series of events such that to about the nearest 5ms, the starting time of event N is t0 + dt*N, where t0 is some arbitrary time after the process starts. If the events were output to a terminal, they would occur regularly without pauses or speedups. If they were noises, it would produce a regular rhythm. This is my first attempt.
#include <stdio.h>
#include <time.h>
#include <math.h>
void fsleep(double t)
{
time_t sec = floor(t);
long nsec = 1e9*(t - sec);
struct timespec s;
s.tv_sec = sec;
s.tv_nsec = nsec;
nanosleep(&s, NULL);
}
int main(int argc, const char **argv)
{
for (unsigned i = 0;; i++) {
printf("%d\n", i);
fflush(stdout);
fsleep(0.334);
}
}
It is total garbage, even at realtime priority (nice -n -20). There are noticeable jitters the entire time, with pauses of up to 1 second, after which a whole bunch of numbers are printed in a row. To test whether it was my terminal, I made the following script:
from time import sleep
from sys import stdin
def raw_stdin():
"""Switches stdin to a non-buffering, non-echoing mode,
handing keystrokes directly to the program as soon as they're
received and printing nothing to the terminal."""
import termios as t
f = t.tcgetattr(stdin)
f[3] &= ~(t.ICANON|t.ECHO)
t.tcsetattr(stdin, t.TCSANOW, f)
raw_stdin()
for i in range(10000000):
#sleep(.334)
stdin.read(1)
print(i)
If I hit any key regularly, i.e. with the same time intervals between strokes down to the nearest 10ms or so, I get regular outputs, with zero hesitations. This proves the terminal is more than responsive enough, and that what I'm trying to do is possible. I have a hard time imagining the computer can't do something I can do with my left index finger.
I think it might have something to do with my linux kernel. I'd be interested to know what happens if this is run in windows, or on other linux kernels.
I figured it out. It was my terminal all along (xfce4-terminal). There's a bug in it that messes up realtime output. See https://stackoverflow.com/a/47744798/1840698 for more.
My question is a little tricky, and I'm not exactly experienced (I might get some terms wrong), so here goes.
I'm declaring an instance of an object called "Singer". The instance is called "singer1". "singer1" produces an audio signal. Now, the following is the code where the specifics of the audio signal are determined:
OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
//Singer *me = (Singer *)inRefCon;
static int phase = 0;
for(UInt32 i = 0; i < ioData->mNumberBuffers; i++) {
int samples = ioData->mBuffers[i].mDataByteSize / sizeof(SInt16);
SInt16 values[samples];
float waves;
float volume=.5;
for(int j = 0; j < samples; j++) {
waves = 0;
waves += sin(kWaveform * 600 * phase)*volume;
waves += sin(kWaveform * 400 * phase)*volume;
waves += sin(kWaveform * 200 * phase)*volume;
waves += sin(kWaveform * 100 * phase)*volume;
waves *= 32500 / 4; // <--------- make sure to divide by how many waves you're stacking
values[j] = (SInt16)waves;
values[j] += values[j]<<16;
phase++;
}
memcpy(ioData->mBuffers[i].mData, values, samples * sizeof(SInt16));
}
return noErr;
}
99% of this is borrowed code, so I only have a basic understanding of how it works (I don't know about the OSStatus class or method or whatever this is. However, you see those 4 lines with 600, 400, 200 and 100 in them? Those determine the frequency. Now, what I want to do (for now) is insert my own variable in there in place of a constant, which I can change on a whim. This variable is called "fr1". "fr1" is declared in the header file, but if I try to compile I get an error about "fr1" being undeclared. Currently, my technique to fix this is the following: right beneath where I #import stuff, I add the line
fr1=0.0;//any number will work properly
This sort of works, as the code will compile and singer1.fr1 will actually change values if I tell it to. The problems are now this:A)even though this compiles and the tone specified will play (0.0 is no tone), I get the warnings "Data definition has no type or storage class" and "Type defaults to 'int' in declaration of 'fr1'". I bet this is because for some reason it's not seeing my previous declaration in the header file (as a float). However, again, if I leave this line out the code won't compile because "fr1 is undeclared". B)Just because I change the value of fr1 doesn't mean that singer1 will update the value stored inside the "playbackcallback" variable or whatever is in charge of updating the output buffers. Perhaps this can be fixed by coding differently? C)even if this did work, there is still a noticeable "gap" when pausing/playing the audio, which I need to eliminate. This might mean a complete overhaul of the code so that I can "dynamically" insert new values without disrupting anything. However, the reason I'm going through all this effort to post is because this method does exactly what I want (I can compute a value mathematically and it goes straight to the DAC, which means I can use it in the future to make triangle, square, etc waves easily). I have uploaded Singer.h and .m to pastebin for your veiwing pleasure, perhaps they will help. Sorry, I can't post 2 HTML tags so here are the full links.
(http://pastebin.com/ewhKW2Tk)
(http://pastebin.com/CNAT4gFv)
So, TL;DR, all I really want to do is be able to define the current equation/value of the 4 waves and re-define them very often without a gap in the sound.
Thanks. (And sorry if the post was confusing or got off track, which I'm pretty sure it did.)
My understanding is that your callback function is called every time the buffer needs to be re-filled. So changing fr1..fr4 will alter the waveform, but only when the buffer updates. You shouldn't need to stop and re-start the sound to get a change, but you will notice an abrupt shift in the timbre if you change your fr values. In order to get a smooth transition in timbre, you'd have to implement something that smoothly changes the fr values over time. Tweaking the buffer size will give you some control over how responsive the sound is to your changing fr values.
Your issue with fr being undefined is due to your callback being a straight c function. Your fr variables are declared as objective-c instance variables as part of your Singer object. They are not accessible by default.
take a look at this project, and see how he implements access to his instance variables from within his callback. Basically he passes a reference to his instance to the callback function, and then accesses instance variables through that.
https://github.com/youpy/dowoscillator
notice:
Sinewave *sineObject = inRefCon;
float freq = sineObject.frequency * 2 * M_PI / samplingRate;
and:
AURenderCallbackStruct input;
input.inputProc = RenderCallback;
input.inputProcRefCon = self;
Also, you'll want to move your callback function outside of your #implementation block, because it's not actually part of your Singer object.
You can see this all in action here: https://github.com/coryalder/SineWaver