Audio issue with IMX6 board (max98357a codec) - audio

I'am working on a custom board based on IMX6 Solo processor and TX6S-8035 module, trying to play audio with MAX98357a codec. I just start leaning how works the device-tree I implement a simple-audio-card on the 4.1.15 linux kernel and use the following DTS as suggested in i.MX6 and MA98357a with simple-audio-card:
codec: max98357a#0 {
compatible = "maxim,max98357a";
#sound-dai-cells = <0>;
};
sound {
compatible = "simple-audio-card";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ssi1>;
simple-audio-card,name = "TI3 Audio";
simple-audio-card,format = "i2s";
simple-audio-card,widgets = "Speaker", "Speakers";
simple-audio-card,routing = "Speakers", "Speaker";
simple-audio-card,bitclock-master = <&cpu_dai>;
simple-audio-card,frame-master = <&cpu_dai>;
cpu_dai: simple-audio-card,cpu {
sound-dai = <&ssi1>;
system-clock-frequency = <883200>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <16>;
};
codec_dai: simple-audio-card,codec {
sound-dai = <&codec>;
};
};
&audmux {
status = "okay";
// Note: 'ssi1' (node of first SSI) corresponds to '_SSI0' below.
ssi1 {
fsl,audmux-port = <MX31_AUDMUX_PORT1_SSI0>;
fsl,port-config = <
0x00000000
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT3_SSI_PINS_3)
>;
};
aud3 {
fsl,audmux-port = <MX31_AUDMUX_PORT3_SSI_PINS_3>;
fsl,port-config = <
(IMX_AUDMUX_V2_PTCR_TFSDIR |
IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT1_SSI0) |
IMX_AUDMUX_V2_PTCR_TCLKDIR |
IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT1_SSI0))
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0)
>;
};
};
&ssi1 {
fsl,mode = "i2s-master";
assigned-clocks = <&clks IMX6QDL_CLK_SSI1_SEL>, <&clks IMX6QDL_CLK_SSI1>;
assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <0>, <49152000>; // 48kHz on SSI1 clock
status = "okay";
};
The MAX98357a codec is connected to SSI1. The soundcard is detected by ALSA. But when i try to play an audio file, i have nothing out on the speaker and there is no I2S signal on the SSI1 pin. Does somebody has any idea for this issue.
Thanks.
Best Regard!

I had some trouble getting the sound card (MA98357a codec with the simple-audio-card) to work with a recent revision of the imx6q (i.MX 6 Quad), so I am sharing here my solution:
CONFIG_SND_SOC_MAX98357A needs to be enabled (associated with the compatible "maxim,max98357a"). But "by default" this option cannot be selected under make menuconfig. The associated Kconfig (sound/soc/codecs/Kconfig) needs to be patched. Replace:
config SND_SOC_MAX98357A
tristate
By:
config SND_SOC_MAX98357A
tristate "Maxim MAX98357A CODEC"
CONFIG_SND_SIMPLE_CARD needs to be enabled (associated with the compatible "simple-audio-card")
Apply/Merge/Cherry-pick the following patch, if not already applied: Commit id in master: 3ff86050da41e072dd9fffc373c4f5691573cf4e: clk: imx6q: disable non functional divider. I had to "merge" it manually since I am using an older kernel version 4.19.134
Write the .dts for this audio card:
Configure audmux, in my case the pins (TXD, CLK, FS) are connected to AUD5 pins. The first SSI (ssi1) is used. This SSI is going to generate the bit clock (CLK) and provide it to the max98357a audio card.
Configure the iomux: the AUD5 pins needs to be configured in the right mode
Configure ssi1 and the associated clock. The best clock for that is the PLL4, which is the only clock that allow to generate exactly 48 kHz.
Add the codec and the sound card
Below an extract of the .dts:
/dts-v1/;
#include <dt-bindings/sound/fsl-imx-audmux.h>
#include "imx6q.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"
/ {
codec: max98357a#0 {
compatible = "maxim,max98357a";
#sound-dai-cells = <0>;
};
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "max98357a";
simple-audio-card,format = "i2s";
simple-audio-card,widgets = "Speaker", "Speakers";
simple-audio-card,routing = "Speakers", "Speaker";
simple-audio-card,bitclock-master = <&cpu_dai>;
simple-audio-card,frame-master = <&cpu_dai>;
cpu_dai: simple-audio-card,cpu {
sound-dai = <&ssi1>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <16>;
};
codec_dai: simple-audio-card,codec {
sound-dai = <&codec>;
clocks = <&clks IMX6QDL_CLK_SSI1>;
};
};
};
&audmux {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_audmux>;
status = "okay";
ssi1 {
fsl,audmux-port = <MX31_AUDMUX_PORT1_SSI0>;
fsl,port-config = <
0x00000000
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5)
>;
};
aud5 {
fsl,audmux-port = <MX31_AUDMUX_PORT5_SSI_PINS_5>;
fsl,port-config = <
(IMX_AUDMUX_V2_PTCR_TFSDIR |
IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT1_SSI0) |
IMX_AUDMUX_V2_PTCR_TCLKDIR |
IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT1_SSI0))
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0)
>;
};
};
/* The clock tree used to generate the SSI1 bit clock (See IMX6DQRM reference manual):
* pll4 -- 24e6 * (DIV_SELECT + NUM/DENOM)
* pll4_bypass -- Bypass PLL4: CCM_ANALOG_PLL_AUDIO[BYPASS]
* pll4_audio -- Enable PLL4: CCM_ANALOG_PLL_AUDIO[ENABLE]
* pll4_post_div -- Divide PLL4: CCM_ANALOG_PLL_AUDIO[POST_DIV_SELECT]
* pll4_audio_div -- Reserved: Fixed factor of x1
* ssi1_sel -- Clock multiplexer
* ssi1_pred -- Divide SSI1: CS1CDR[SSI1_CLK_PRED]
* ssi1_podf -- Divide SSI1: CS1CDR[SSI1_CLK_PODF]
* ssi1 (SSI1_CLK_ROOT) -- Clock gate: CCM_CCGR5[CG9]
* ssi1 (Int. bit clock) -- Divide SSI1: STCCR[DIV2, PSR, PM] (See formula below)
*
* With the following constraint:
* - (DIV_SELECT + NUM/DENOM): Must be between 27 and 54: PLL4 clock between 650 and 1300 MHz
* - DENOM = 24e6: As implemented in clk_pllv3_av_set_rate()
* - POST_DIV_SELECT: Can divide by [1; 2; 4]
* - SSI1_CLK_PRED: Can divide by [1, 8]
* - SSI1_CLK_PODF: Can divide by [1, 64]
* - DIV2 and PSR = 0: As implemented in fsl_ssi_set_bclk()
* - PM > 0: Since DIV2, PSR and PM should not be all set to zero at the same time.
* - SSI bit clock = SSI1_CLK_ROOT / ((DIV2 + 1) * (7 * PSR + 1) * (PM + 1) * 2)
*
* SSI bit clock needs to be equal to 3072000 Hz (for 2 channels/stereo, 48kHz) since:
* - For 2 channels, slot width is fixed to 32 bits since in I2S Master mode, and STCCR[WL] are
* used to control the amount of valid data in those 32 bits.
* - 2 slots are used, one for each channel. The slot number (STCCR[DC]) is fixed to 2.
* => SSI bit clock = 48000 * 32 * 2 = 3072000
*
* SSI bit clock needs to be equal to 1536000 Hz (for 1 channel/mono, 48kHz) since:
* - Slot width is set to 16 bits, in I2S Normal mode.
* - 2 slots are used (fixed to 2), and data are only provided in first slot
* => SSI bit clock = 48000 * 16 * 2 = 1536000
*
* So SSI1_CLK_ROOT frequency needs to be equal to: 3072000 * (PM + 1) * 2 = 6144000 * (PM + 1)
*
* The following configuration is applied:
* - SSI1_SEL parent clock is configured to be PLL4_AUDIO_DIV
* - SSI1_SEL clock is automatically configured
* - PLL4 clock is set to 663.552 MHz, which is a multiple of 6144000 Hz (x 108).
* The PLL4 must be configured in the DTS otherwise Linux keeps the default/reset values, which
* are invalid. /sys/kernel/debug/clk/clk_summary report 147456000 Hz but the generated clock
* is not at this frequency.
* - SSI1_CLK_ROOT is set to 18.432 MHz. (18.432 * 36 = 663.552 MHz)
* - STCCR[PM] will be automatically set to 2. (18.432 / (2 + 1) / 2 = 3.072 MHz)
*/
&ssi1 {
fsl,mode = "i2s-master";
assigned-clocks = <&clks IMX6QDL_CLK_SSI1_SEL>, <&clks IMX6QDL_CLK_PLL4>, <&clks IMX6QDL_CLK_SSI1>;
assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <0>, <663552000>, <18432000>;
status = "okay";
};
/* For iomuxc, pin configuration (pad setting value):
* - Bit 0: Slew rate: 1 = fast, 0 = slow
* - Bit 3-5: Drive Strength: 0 = HI-Z, 1 = 260 Ohm, 2 = 130 Ohm, 3 = 90 Ohm, 4 = 60 Ohm, 5 = 50 Ohm, 6 = 40 Ohm, 7 = 33 Ohm
* - Bit 6-7: Speed: 0 = Low, 1 and 2 = Medium, 3 = Maximum
* - Bit 11: Open drain: 0 = Disabled, 1 = Enabled
* - Bit 12: Pull / Keep Enable: 0 = Disabled, 1 = Enabled
* - Bit 13: Pull / Keep Select: 0 = Keep, 1 = Pull
* - Bit 14-15: Pull Up / Down config: 0 = 100K Down, 1 = 47K Up, 2 = 100K Up, 3 = 22K Up
* - Bit 16: Hysteresis Enable: 0 = Disabled, 1 = Enabled
* - Bit 30: SION: Software Input On Field.
* - Bit 31: NO_PAD_CTL: indicate this pin does not need config.
*
* See fsl,imx-pinctrl.txt, fsl,imx6q-pinctrl.txt, and pinctrl-bindings.txt
* See also https://www.nxp.com/docs/en/application-note/AN5078.pdf
*/
&iomuxc {
pinctrl_audmux: audmuxgrp {
fsl,pins = <
MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 /* AUDIO: DIN, D56, X_AUD5_TXD, SSI1_TXD */
MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 /* AUDIO: BCLK, D53, X_AUD5_TXC, SSI1_CLK */
MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 /* AUDIO: LRCLK, D54, X_AUD5_TXFS, SSI1_FS */
>;
};
};

Related

STM F767 Read SDRAM with FMC

I try to write 1 byte and then read 1 byte from SDRAM IS42S81600F. It's connected to FMC pins of Nucleo-F767 board. In debug mode program goes to hard fault handler after reading. I'm using FMC configuration from CubeMX and initialization code found in some tutorial. Is it a problem in writing and reading code or in initialization? HCLK is set to 96 MHz.
This is how i try to write and read:
*(__IO uint8_t*) (SDRAM_ADDRESS_START) = (uint8_t) 0x55; //SDRAM_ADDRESS_START is 0xC0000000
byte = *(__IO uint16_t*) (SDRAM_ADDRESS_START);
Initialization:
__IO uint32_t tmpmrd =0;
command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.AutoRefreshNumber = 1;
command.ModeRegisterDefinition = 0;
hal_stat = HAL_SDRAM_SendCommand(&hsdram1, &command, SDRAM_TIMEOUT);
HAL_Delay(1);
command.CommandMode = FMC_SDRAM_CMD_PALL;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.AutoRefreshNumber = 1;
command.ModeRegisterDefinition = 0;
hal_stat = HAL_SDRAM_SendCommand(&hsdram1, &command, SDRAM_TIMEOUT);
HAL_Delay(1);
command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.AutoRefreshNumber = 8;
command.ModeRegisterDefinition = 0;
hal_stat = HAL_SDRAM_SendCommand(&hsdram1, &command, SDRAM_TIMEOUT);
HAL_Delay(1);
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_2 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.AutoRefreshNumber = 1;
command.ModeRegisterDefinition = tmpmrd;
hal_stat = HAL_SDRAM_SendCommand(&hsdram1, &command, SDRAM_TIMEOUT);
/* Step 8: Set the refresh rate counter */
/* (15.62 us x Freq) — 20 */
/* Set the device refresh counter */
HAL_SDRAM_ProgramRefreshRate(&hsdram1, 1480);
I've tried to change timings and clock settings in CubeMX configurator, but with no luck.

ESP32 reading DHT22 sensor in ULP coprocessor

I´m trying to read a dht22 sensor in ulp deep sleep, and it´s not working, can perhaps someone tell me what I´m doing wrong?
I´m reimplementing the arduino-DHT library because it´s working in non ulp mode with my sensor, it looks like this:
digitalWrite(pin, LOW); // Send start signal
pinMode(pin, OUTPUT);
delayMicroseconds(800);
pinMode(pin, INPUT);
digitalWrite(pin, HIGH); // Switch bus to receive data
// We're going to read 83 edges:
// - First a FALLING, RISING, and FALLING edge for the start bit
// - Then 40 bits: RISING and then a FALLING edge per bit
// To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long
uint16_t rawHumidity = 0;
uint16_t rawTemperature = 0;
uint16_t data = 0;
for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
byte age;
startTime = micros();
do {
age = (unsigned long)(micros() - startTime);
if ( age > 90 ) {
error = ERROR_TIMEOUT;
return;
}
}
while ( digitalRead(pin) == (i & 1) ? HIGH : LOW );
if ( i >= 0 && (i & 1) ) {
// Now we are being fed our 40 bits
data <<= 1;
// A zero max 30 usecs, a one at least 68 usecs.
if ( age > 30 ) {
data |= 1; // we got a one
}
}
switch ( i ) {
case 31:
rawHumidity = data;
break;
case 63:
rawTemperature = data;
data = 0;
break;
}
}
Looks simple enough :D, I tried the first part with this code, but it doesn´t work:
rtc_gpio_init(15);
rtc_gpio_set_direction(15, RTC_GPIO_MODE_INPUT_OUTPUT);
And in my ulp script file:
.set temp_humidity_sensor_pin, 13 // gpio 15 (adc 13)
send_start_signal:
/* disable hold on gpio 15 (data pin) */
WRITE_RTC_REG(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_HOLD_S, 1, 0)
/* switch to output mode */
WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + temp_humidity_sensor_pin, 1, 1)
/* send start signal (LOW) */
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + temp_humidity_sensor_pin, 1, 0)
/* pull low for 800 microseconds (8Mhz) */
wait 6400
/* switch to input mode */
WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S + temp_humidity_sensor_pin, 1, 1)
/* switch bus to receive data (HIGH) */
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + temp_humidity_sensor_pin, 1, 1)
wait_for_sensor_preparation_low:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 1
jump wait_for_sensor_preparation_low, eq
wait_for_sensor_preparation_high:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 0
jump wait_for_sensor_preparation_high, eq
jump wake_up // <-- never called :(
Any ideas?
Your "and r0, r0, 0" instruction (near the end) always sets r0 to zero (x & 0 == 0 by definition), which means the following jump instruction will loop forever. Remember that the "eq" flag doesn't really mean "equal". It means "zero". I think you want:
wait_for_sensor_preparation_low:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 1
jump wait_for_sensor_preparation_high, eq
jump wait_for_sensor_preparation_low
wait_for_sensor_preparation_high:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 1
jump wait_for_sensor_preparation_high, eq
By the way, I wrote a C compiler for the ULP, which should make your life easier. It's on https://github.com/jasonful/lcc

Can SuperpoweredFloatToShortIntInterleave be used to process media playback from devices?

I am having some issues with understanding Superpowered audio output processing. Everything was fine when I was using SuperpoweredFloatToShortInt input buffers as;
buffer[n] = (float *)memalign(16, (buffersize + 16) * sizeof(float) * 2);)
then I realised my audio output have been mono all this while so I decided to process my output using SuperpoweredFloatToShortIntInterleave to give out surround stereo effect. Using the same buffer[n] variable, my audio got processed but was distorted and low-pitched towards bass when testing on device.
I have also tried having separate buffer variables as learnt here
with these:
inputBufferFloat = (float *)malloc(buffersize * sizeof(float) * 2 + 128);
leftInputBuffer = (float *)malloc(buffersize * sizeof(float) + 128);
rightInputBuffer = (float *)malloc(buffersize * sizeof(float) + 128);
leftOutputBuffer = (float *)malloc(buffersize * sizeof(float) + 128);
rightOutputBuffer = (float *)malloc(buffersize * sizeof(float) + 128)
static bool audioProcessing(void * __unused clientdata, short int *audioInputOutput, int numberOfSamples, int
__unused samplerate) {
SuperpoweredShortIntToFloat(audioInputOutput, inputBufferFloat, numberOfSamples, 2);
SuperpoweredDeInterleave(inputBufferFloat, leftInputBuffer, rightInputBuffer, numberOfSamples);
FIR(leftInputBuffer, leftOutputBuffer, numberOfSamples);
FIR(rightInputBuffer, rightOutputBuffer, numberOfSamples);
SuperpoweredFloatToShortIntInterleave(leftOutputBuffer, rightOutputBuffer, audioInputOutput,
numberOfSamples);
return true;
}
But the app crashes instantly at test. Please, any help at all will be much appreciated.
Thanks.
You may set up the audio I/O with a different "buffersize", such as "buffersize" multiplied by two. In this case your "numberOfSamples" will be twice as big and your buffers not big enough.

Calculating collisions with Radians incrementing

While programming a game with the Tululoo Game Maker API, I am having problems with calculating collisions accurately as the x and y are being calculated from the radians.
The calculations for x and y below are producing a large number number of decimal points which I am finding difficult to check for collisions.
image_angle is the final angle of the pistol in degrees that the bullet uses initially.
In Setup:
x = instance_list(pistol)[0].x;
y = instance_list(pistol)[0].y;
startAng = instance_list(pistol)[0].image_angle;
this.travelX = cos(degtorad(instance_list(pistol)[0].image_angle)) * 5;
this.travelY = sin(degtorad(instance_list(pistol)[0].image_angle)) * 5;
In Update Frame:
x+=this.travelX;
y+=this.travelY;
Calculating the Angle that the ball will bounce off a wall at, messy I know:
for(var i = 0; i < instance_number(bounce_barrier);i++){
if(place_meeting(x,y,instance_list(bounce_barrier)[i])){
if(Math.round(x*10)/10 > instance_list(bounce_barrier)[i].x ){
newAng = 180 - startAng;
this.travelX = +cos(degtorad(newAng)) * 15;
this.travelY = +sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else if(y > instance_list(bounce_barrier)[i].y - 5 && y <= instance_list(bounce_barrier)[i].y + 10){
newAng = 180 - startAng;
this.travelX = -cos(degtorad(newAng)) * 15;
this.travelY = -sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else if(y <= instance_list(bounce_barrier)[i].y - 5 + bounce_spr.height && y >= instance_list(bounce_barrier)[i].y + bounce_spr.height - 10){
newAng = 180 - startAng;
this.travelX = -cos(degtorad(newAng)) * 15;
this.travelY = -sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else if(x < instance_list(bounce_barrier)[i].x){
newAng = 180 - startAng;
this.travelX = +cos(degtorad(newAng)) * 15;
this.travelY = +sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else{}
}
}
place_meeting is Part of the Tululoo Game API:
function __place_meeting__(nx, ny, what, many) {
this.other = null;
var i, l,
// sprite, scale:
ts = this.sprite_index,
tsx, tsy, tfx, tfy, tst,
// circle:
tcx, tcy, tcr,
// bbox:
tbl, tbr, tbt, tbb,
// instances, multiple, output, types:
tz, tm, ct, ch, ra,
// other:
o, ox, oy, os, ost, osx, osy, ofx, ofy, ofr;
if (ts == null) return false;
tfx = ts.xoffset;
tfy = ts.yoffset;
tsx = this.image_xscale;
tsy = this.image_yscale;
tst = ts.collision_shape;
// bbox:
if (tst == 2) {
tbl = nx + tsx * (ts.collision_left - tfx);
tbr = nx + tsx * (ts.collision_right - tfx);
tbt = ny + tsy * (ts.collision_top - tfy);
tbb = ny + tsy * (ts.collision_bottom - tfy);
}
// circle:
if (tst == 3) {
tcr = ts.collision_radius * (tsx > tsy ? tsx : tsy);
tcx = nx + tsx * (ts.width / 2 - tfx);
tcy = ny + tsy * (ts.height / 2 - tfy);
}
//
tz = (what.__instance ? [what] : instance_list(what));
tm = many ? true : false;
if (tm) ra = [];
l = tz.length;
for (i = 0; i < l; i++) {
o = tz[i];
if (!o.collision_checking) continue;
os = o.sprite_index;
if (os == null) continue;
ox = o.x; osx = o.image_xscale;
oy = o.y; osy = o.image_yscale;
ost = os.collision_shape;
ct = (tst << 4) | ost;
ch = false;
switch(ct) {
case 0x22:
if (osx == 1 && osy == 1) {
ofx = os.xoffset; ofy = os.yoffset;
if (!collide_bbox_bbox(tbl, tbt, tbr, tbb,
ox + os.collision_left - ofx, oy + os.collision_top - ofy,
ox + os.collision_right - ofx, oy + os.collision_bottom - ofy)) break;
} else if (!collide_bbox_sbox(tbl, tbt, tbr, tbb, ox, oy, osx, osy, os)) break;
ch = true;
break;
case 0x23:
ofr = os.collision_radius * (osx > osy ? osx : osy);
ofx = ox + osx * (os.width / 2 - os.xoffset);
ofy = oy + osy * (os.height / 2 - os.yoffset);
if (!collide_bbox_circle(tbl, tbt, tbr, tbb, ofx, ofy, ofr)) break;
ch = true;
break;
case 0x32:
if (osx == 1 && osy == 1) {
ofx = os.xoffset; ofy = os.yoffset;
if (!collide_bbox_circle(
ox + os.collision_left - ofx, oy + os.collision_top - ofy,
ox + os.collision_right - ofx, oy + os.collision_bottom - ofy,
tcx, tcy, tcr)) break;
} else if (!collide_sbox_circle(ox, oy, osx, osy, os, tcx, tcy, tcr)) break;
ch = true;
break;
case 0x33:
ofr = os.collision_radius * (osx > osy ? osx : osy);
ofx = ox + osx * (os.width / 2 - os.xoffset);
ofy = oy + osy * (os.height / 2 - os.yoffset);
if (!collide_circle_circle(tcx, tcy, tcr, ofx, ofy, ofr)) break;
ch = true;
break;
} if (!ch) continue;
this.other = o;
o.other = this;
if (!tm) return (o);
ra.push(o);
} return ra;
}
I have managed to make a bullet bounce off a wall at an angle proportional to where it has been shot from, but the collision detection is very bad as it bounces some bullets but not all, some just go straight through the wall.
Just added the Line Collision Detection, ive made the bullets lines so I can see the
this.oldTravelX,this.oldTravelY to this.travelX,this.travelY. It has definitely improved but some of the bullets are still going through.
Some bullets seem to stick inside the bouncing block or slide down the left side of the bouncing block then decide whether to go left or right.
Updated Code:
pntdis = point_distance(this.oldTravelX, this.oldTravelY, this.travelX, this.travelY);
noPoints = pntdis/0.01;
for(var i=0; i < pntdis; i+=noPoints)
{
pointsArrX[i] = this.travelX - (this.oldTravelX * i);
pointsArrY[i] = this.travelY - (this.oldTravelY * i);
}
for(var i=0;i<pointsArrX.length;i++){
if(place_meeting(Math.round(pointsArrX[i]),Math.round(pointsArrY[i]),bounce_barrier) || place_meeting(x,y,bounce_barrier))
{
newAng = 180 - startAng;
this.travelX = +cos(degtorad(newAng)) * 15;
this.travelY = +sin(degtorad(newAng)) * 15;
startAng = newAng;
}
}
Thanks in advance.
It looks like the place_meeting function is supposed to determine whether there's a collision between the bullet and the barrier. However, this function only takes the new position of the bullet. Given the bullet moves 5 units per update, it's possible that the bullet could move from one side of the barrier to the other in a single frame. e.g.:
|
. |
\| barrier
\
|\_______
\
.
place_meeting should take both the old and new positions of the bullet so that it can determine whether any intermediate position collided with the barrier (e.g. by doing line-line intersection testing with the path of the bullet and the edges of the barrier; it should probably also return the collision point).
EDIT
Your updated code looks like it's intended to check for collision of a number of points along the path of the bullet. There are faster ways to do this, but your method may be fast enough, and is easy to understand. There appears to be a bug in how you calculate the points to check though.
Stepping through the code manually on paper:
pntdis = 5 // assume point_distance returns 5
noPoints = 5 / 0.01 = 500
i = 0
pointsArrX[0] = this.travelX
pointsArrY[0] = this.travelY
i = i + noPoints = 500
500 < 5: false, for loop ends
Other things to consider:
You might want a break statement after you've detected a collision so you don't keep testing further points.
You could combine the two for loops into one because you're not reusing the values in the array. Just calculate your test point and then test it immediately.
Try using console.log to output debugging information as your program runs so you can get a better idea of what's happening.
Use var before your variables (such as pntdis and noPoints) to avoid accidentally creating global variables.

frequency modulation (FM) code snippet

I've written the following code for frequency modulation of an audio signal. The audio itself is 1 sec long, sampled at 8000 Hz. I want to apply FM to this audio signal by using a sine wave with a frequency of 50 Hz (expressed as a fraction of the sampling frequency). The modulating signal has a modulation index of 0.25 so as to create only one pair of sidebands.
for (i = 0; i < 7999; i++) {
phi_delta = 8000 - 8000 * (1 + 0.25 * sin(2* pi * mf * i));
f_phi_accum += phi_delta; //this can have a negative value
/*keep only the integer part that'll be used as an index into the input array*/
i_phi_accum = f_phi_accum;
/*keep only the fractional part that'll be used to interpolate between samples*/
r_phi_accum = f_phi_accum - i_phi_accum;
//If I'm getting negative values should I convert them to positive
//r_phi_accum = fabs(f_phi_accum - i_phi_accum);
i_phi_accum = abs(i_phi_accum);
/*since i_phi_accum often exceeds 7999 I have to add this if statement so as to prevent out of bounds errors */
if (i_phi_accum < 7999)
output[i] = ((input[i_phi_accum] + input[i_phi_accum + 1])/2) * r_phi_accum;
}
Your calculation of phi_delta is off by a factor of 8000 and an offset - it should be 1 +/- a small value, i.e.
phi_delta = 1.0 + 0.25 * sin(2.0 * pi * mf * i));
which will result in phi_delta having a range of 0.75 to 1.25.

Resources