Sound volume based on distance

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
jinxtengu
Posts: 122
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Sound volume based on distance

Post by jinxtengu »

Hi.

I wanted to find a way to code Sound effects so that
the volume of a sound is louder the closer one
is to the object which is emitting the sound.
I am using .ogg as the primary sound format.


Lets say for example a cricket is chirping in the game,
and we wanted the sound to be audible as the player
approaches the source of the sound.


would we call an expression just before the sound is called
which performs a calculation of distance and sets
sample volume based on a ratio of that distance?


Again I may need to be reminded of how to code
relational distance between two models.
Any Ideas? :D
User avatar
Kjell
Posts: 1883
Joined: Sat Feb 23, 2008 11:15 pm

Re: Sound volume based on distance

Post by Kjell »

Hi jinxtengu,
jinxtengu wrote: Sun May 07, 2023 7:12 amI wanted to find a way to code Sound effects so that the volume of a sound is louder the closer one is to the object which is emitting the sound.
Simply calculate the distance between the sound source / emitter and the camera and set the sound volume accordingly. Here's a example ( press left mouse button to walk ).

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" CameraPosition="0 1 10" FileVersion="2">
  <OnLoaded>
    <SpawnModel Model="Cricket" Position="0 0.25 0" SpawnStyle="1"/>
    <ZExpression>
      <Expression>
<![CDATA[//

CricketSample.Length = 12000/44100;]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[//

Mouse[1] = Mouse[0];
Mouse[0] = App.MousePosition.X;]]>
      </Expression>
    </ZExpression>
    <KeyPress Keys="{">
      <OnPressed>
        <ZExpression>
          <Expression>
<![CDATA[// Simple debug camera control

float dt = App.DeltaTime;

//

App.CameraRotation.Y += (Mouse[0]-Mouse[1])*8*dt;

float a = App.CameraRotation.Y*PI*2;

App.CameraPosition.X += sin(a)*4*dt;
App.CameraPosition.Z -= cos(a)*4*dt;]]>
          </Expression>
        </ZExpression>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <OnRender>
    <UseMaterial Material="GridMaterial"/>
    <RenderMesh Mesh="GridMesh"/>
  </OnRender>
  <Content>
    <Array Name="Mouse" SizeDim1="2"/>
    <Model Name="Cricket" Position="0 0.25 0">
      <Definitions>
        <Variable Name="CricketTimer"/>
      </Definitions>
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[//

float a, s, x, z;

// Get position relative to camera

x = Cricket.Position.X - App.CameraPosition.X;
z = Cricket.Position.Z - App.CameraPosition.Z;

// Calculate distance to camera

s = sqrt(x*x+z*z);

CricketSound.Volume = clamp(1/log2(s), 0, 1);

// Calculate panning from normalized vector

a = App.CameraRotation.Y*PI*2;

x /= s;
z /= s;

CricketSound.Pan = (x*cos(a)+z*sin(a))+0.5;

// When timer runs out play sound random number of times

CricketTimer -= App.DeltaTime;

if(CricketTimer < 0)
{
  CricketTimer += 2;

  CricketSound.Length = CricketSample.Length*floor(1+rnd()*4)-0.02;
  @PlaySound(Sound: CricketSound, ByReference: 1);
}]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="CricketMaterial"/>
        <RenderMesh Mesh="CricketMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="CricketMesh">
      <Producers>
        <MeshSphere ZSamples="4" RadialSamples="4"/>
        <MeshExpression Scale="0.5 0.25 0.5" Expression="//"/>
      </Producers>
    </Mesh>
    <Material Name="CricketMaterial" Shading="1" Color="0.502 1 0.502 1"/>
    <Sound Name="CricketSound" Length="0.8163" Volume="0.301" Sample="CricketSample" UseSampleHz="255"/>
    <Sample Name="CricketSample" Length="0.2721">
      <Producers>
        <SampleImport SampleFileFormat="1">
          <SampleData>
<![CDATA[78DAD5577B38945DD7DFE314A1E6293234344A654A8590F1AA87898C53324C0C4D72981C0735333AEA99278784248D7918D3E4D4C8D054928A128A3424724A52A44C99D299228F77CFE8F9DEE7BBAEF7BBDEEBFBE3FBE3BBAF7DEF7BEDB5D7FDDB6BADBDF6BAD7ED111AEA0514C0CFCB69FDEC7391D5DB2B0803445CCCDEA070BA8C8170289F9D61D5CC3EAF233C646F82BFBF8980CF62BBD1E9F9FF98F9FB65AE388BB31A4EFB86C786ADF5D81B8A890A0FDA2EE7629C31E6A666E6A6E6A6EB31C61EB4E8F0D8BD543A359A81952FAB3CFBEA12FCE6ED08D902A8606FEC965CE22397E3BA74B6D996DCA02C97E3E71217E10967E85A5EA5B85E5E64F98DAB9844A49ED736AC722E318318AE1B9C29A390AECECB190B6C569E0946FA3BD7F7E444A6D957A11335B94437EC5D363115AFAAEB958E6D64135DF0739633E6D98CA0BD325C8CEDAFF3E86557399CE0B45246968BC428C40D4FC02665B9CC39E7B5154FB0E4F410B1FA742231C2FE355C125F8549D43CDA9E4992E9596787D4AB980BB601804C2D40A52A2426972B00730094F28D335E18672CC365053B2F928B40E72301A88BD5723EA575FFB291EB2313D74E074F527CB7158934CEA4F4CA1AC622445B866A4728C93DA78769D00841A96A92950106BA688B710352F12FF78020635CCA8ACA91C3F48C84DDB8B0558D238CD8A5DD23CED1AB464678F436DCCA3C7A93B584474FDDBBDB2C0CCAF1E80B1276636729FEDD11FB48A18C6AC29524ECD9828272DCCA11FB08AB1EC85B5429C045AC6D84D4D25723CEB4B5DD723CC9CF4EA853428FDD2A432E1C1FF18BC6EB406A936EC9213ADE5AF277B959F7407BED5156C97B4A3084B345BFA31C53C29B8BE70C14DD310AD3D83BB7D4A9A8E8147114C3F66E72C69E99B55C1500C3442D22C130E9679762988C0A6AC696F08ECE5D555A5C986A2E36B9D26ADE22EBA497AEB4D9BC35BD8BDCAC71A17281ABFBD56EDFE00B3724BCC8798FFCC22F5CED71C19E83BB8C95FB8F057551D50DC9B4DF320B2AE0ED1563CFE72BC8DDC902F273617B9FEEE0C4F857BB47B775623B38C356E9D6D2E5E6A14DEACEA6F8F75007C669813A710313CCE713CCE1DEA4403287FADFDAACE9D0121612AF3A6BC8395470AB9924FFF436FC5F66CA36B4CE13DDB8C7C869AFD1FD2C13E7D316AE576C1F74DABA7F71F0D472EFF476F461380E543AF6B1DD7B19EE7D0C12F92A855C45EBEBA1057068CF27E2FFD698FA72130900BC26641413528B0919C3D659468802C332007465C1629C5A649D314CC83272E6143BF35F910B774708420F0ACF2BC845EC66CF3300C6DC1758C10B6CE10B5CE1329742AA5FA12042649C5721AD16FDA7B6561EE09900B49F42DF3F858601EE0C0984DCBBE632EFC66ADCCB84410F23FEA78D1E5FA043291DCA7FDF00004C8DEE104D9CE816CE6C6FD7ABDEEE57BD5DB5491EA4FF7459BA775AB843C72E87A70ED4059DA87F85315CBEFCD5336403F234DF6C85E1D59D864AA7B29E99A96827F0CD0B35F63EC30F23130CA0D37E010ED0F226CC3D24BD19E7547A7A014E729EC1D693A0CF651043B18D39410F8CB31F13CB4FD033884E178AD841266BE2D8C413A54D50590534BC4D12A1FA4AC01380443302B6582B281D57C2DB9C8E95E4D093CD46D0F40C9C249F415C25E131B6BADC45C161098F4EB459994DDFEAB2B200C60798036FF582F64C6D841D0FB0ECB36C3D3E5978B22D3CB41CBD18144F0B4AEF27DBEE2F6E5EA48D1DDE242F12ADCF9B44E6D83EB4D8D8E94D7A6841EA8643983B388EA46E5A2793D9CF200D7068FD1314FF45719E24DA8037A57F03A9779CD2371E4FEE61067FB2257D75EB646EEC6450BB99347F268532E1E6C571EFCDA6763269FDD954CA3E6ADF84652783D249A2F631287D71549F6B14F2787C2733E9793635C0874A46C5512692FC7BB35F3128033E549F0DDBE1AC7F6FD2500F3330D7D6830491290F2D283E4C4A800FA5B7C7B2932D43EEF3A690E32032C5A787F9D04286DC6F45F1E1C8907D38CC01064586FC8DE433CE24F7660FF5D08636507A2748E4F124382B43BEC1A4A03691BEC67BC5250D31A8CF7B939E93A329D69C0E667C60366DC8974AC61D19F2E50C4C645321942FAD0FB59DBC2839E0DB9957E3F1C3FB9914DDE801496BF57B8D7BEF8BA7C49DDDB4E0DCF801F2EE807D1943289BDB1F864B8517F344AB354A4CD46FBF93365D99AAAD481749A78470B8AABFE1B2B4F6F38FDA4B26456F271B225A1A2E3DA9327B5A1B6D723B16DD1229159B496B3DAB988703F6CFBDF399C1A41CD84DB937CE640C3B591F11C3AD45C8B676A1D8AEC070B502CB1A014E1A1D2F0C21171A9339C6A982D7D58561D5A2E2704169383FDC8F1BCA15840B2BB05C91493837DC8FBF9BCB2DC915847145915C4179AA00DB2288105784732BDE5657D06A4451FD85E1F261145760525351D62F7A3B5A5D4C16941EE08747F021945C585476801F71901F26E41B0B851142E105A1D0C41FCE725F970A56A6428EE00257B8AA45207C52112EAC8A120A6935C2B79315346935D4842614ACC91346C8902B4CFAABD741AD64C85C49AE40BEAE70B53FBF842B431E392E80E0267902A19823C91542E4D1E3FC483972C41361385786BC264FB0AA45449BAA958A2BA285C228882C952919D552FB5E2C1C931B2857A3624D7FC5FB968AF229B9813235846B5B2A688BAF444D5587717F6AB5AABF62CD5435D4EABD581453262C97CA866393A25869B5E9CD8AA82961F964F5EAFEEA18A979FF78BC030C412F4B5A3F3C273004C7A990D56141F32791FCADDCBBABA83004614A0DB470EF83A7A8C7BDBB9246E6D002ABA84350F81AD57F9CD99BCD0CE88D1FEEA50E8C5457BC6BA9B830252C9BAC1A9B6A88958A3EC00F3A2A16A672D3020D2DBD8A0520056685F4C07433D513C436DC9C024F314E820969B35735CC6EC5A91AB2B3208FCD369760D859445548F9A91BB2D9C4486500B4AC61DE7A9C8FBD6C2D8B1604CB1B8084615FE8CFC2882715C1CE7CE8D55261D53B024772BC301CEE943FE4084A8522A9943BCB918E42FFC839D5D56BB985A590535D21829B2214ADAEA9782B8584502A16994C3508AB45ABA14BA50D97A030DC82FEAA98A7307FD7BE9F6A387501A6F11F0D661A4E0830A8360FD8295B9567C4122D16F98635BB008C226099AA182620F12A8689994417C373EC05305D0FC2CFEA2EBCAEB145882340AE840ED98C2D967D73CFFDFB8EF03F4DFCDBAEB4F87F21FCFFB2CBFEBF01865FE2D4589079F0AFC824C0204BF774C136F112906623A8E07667636C502BAE090D43F1153A11490C5F734D0C63B4B88B48CBA513FDD2A0D07A4971B196FF03DC312231EDF2083772ACB8727BA4C852E2E75766D9CBA33FB851B9285204AB707A8B59AFBCE443FD2CFE94C1A0853560193CBE64D3E0DCE1BBEBAF9056D03D2713798D24A6E32470D1A549B2A1AAA1B76CC840E2CFA3E8B2739298299F8585137D9E8DBCD89EA32F1B16B065472911E9626C289F4D44DAA8FE45C93AA28B9C522B60C34A7CD7EF8AC08EA559B68CA775427991CC05B0BE60A139F9C4B644FB0CFB939AF662CFF59A78375C476ED0D688F5DA5E9938E419C602DD08FBBE9DE6EA307B6300A64E0989C2187FC3ABA698C12236A515A99644BA5497AFA1871E41D4293A243A80CC9C7C42CD75D65AC51DED8D943978553CF2A82FDA0EA1666D3D94BCF2D987C4C5BC7C2FEF518CBCB0D10083F058E583A54BB96597AED735B73F1E7CFD4175F60F0C7C03C07A132B25656495C95A53730B2B6B1BDBFFFA4F63B158F2A79D9C96FF8929859AFDEB4F4C2658FC728717D600BD586FF162949E9E015A4F1FADA7ABA78B5EA2AF8F42A1F4D1BB76A3503A68747048C83E7A3091278EC52BB62BBCE878BEB4B979F2E0BACD835BDE278D5FD1F0C297ECB4D7E2B5451C7D6038B6CE3B00E3317D9DBC68ED7AB65DF19F9BEEDF7D9397D9F534E589727E0106DC559BD1D8DFBC3CAEE3E1DC33E72C765DFB64FCF229454DC14E19A42C3C761BB1DB6071E06F7D31458FC09E7085D61EC1514D3B459052F2DBAF9AFB477D349C4AB2A30C9CD3773829553E62AAA9E4AB3477AEB30C1CB35C3AF2EE98660FE65BC7C9075A804D98983B79F36D344B3530A6333B5EB7A4D9DBE844478E42A23822ACAD65CC8BE540CB7BBCDC2DFE63755F3C76B0154D06E9E2315496CEE760B0CBE1F6C8444F69DAB192A3F5F66D2FA9A0BCEB3550B7534C59285D376137BD85A3CE0BDB59BD958FCA247C7F81074F9F9E4F55CE570177EDDB1109AE5844EC8AE409ED20DAB7AF3853D95C1668CF84A96DD20D21AC099B77EB46248D50178B045D8F45298AF988BBF6D675AF74C1983958C26FBCFBC063C31DD5D825A0B2EBAA8E05D0C4AC904AD2C1F24D413FBCEF9CE4B1FC0A7E8B40ABB09BDD375AAF7BE851B20CF3E9E04482DABD938FD40243638C8B27D3C55455DE49A5AEC52CE4CDA06D6C89771EE39321D247AC94DE2AD23BAD33BD47C5A83E34373A77AB4EA1CE2FA2B36A6B17409B1D7F6F75025BFB30475F1D3AFEA877667A0CE511607148A1B875C4E88CCEF7F12275CCC99BD5558321380FF355F72BBFF63A7A2840A31C14DBB719C3BD922E0900FABC2407C943EB98D8C20916B62D5EA1EBA9205D45EE8FD788B1D2C1BA7DCBB857345CA6BACEE1EB7781BB5D290410F675BE83C691272AB50F2DA3FABE7D1952F5DF93D5907E51255DFC209C7B3387A7B4B4D0206043C39F7E58ED832EE7446A6CB1BBBBE9BA29B1D22F6BD04537EA674213F3DD1CAF972BB0C56383CD86A25F5D91059B68D2357F3ED03F986372CD4AB3FC514A86723EC2E1F573A6C68F697A8EF5C1D51BDB0AF94B96B65A8D82974F1D39EAB2704AB06B985C3D179C5730686E2EE5E46D10E1E7E8F5DDDAB9267E6AE6D57EE5DB3ACA74CD0D04D19ECE452E88D77B798BAD3442379E715B1624F13B333A99539AB055CC1F0483C5012DFAFF200A37ED3B2CB27AA87A5A67BFFA8A3050FEFA0AF3E0D93996ED40CD76EC725DF8E7F10063AD64743AA8BA3E1093BA69F2F6E9CAE4991AE347964F318A8CACFC172BDAD80870B368FED1B4679BA3371D4AE46755BECC429ED1EC07E95969973FDFD959FB0FAB3781202FDEBEDD73A51DC2EEBAEF718E7363D4B34BF7154CF4E39AEABE8897D92BEEBA3C7EF3FE93C983DA80ED52A6FDE97058BB443305A8FD82FCC25E91E4C96EA420D8E2E6F36D69C4A30EB65F0D754AD4B399F589B6B1215B94D8AD4C659B757C578C50782DCDE953502012E5487AB39ADD2A52C8D1B91D00B6F17B6BBF0F180896949E40BF4FB49B4839ABD4FAF8BC8DBA9D268C803FF7598EF31A973FFFB3FAE3A9516BA5CE1A559B37B7286BE28767F69A0C3D4F5B7A3D790E612D7361D00A864ADD1BADA48F3F04394938E292AD030884B457FF7C7F6D15C7420F84DE36B77ABA4374F808CE9CD8DA0A2B0305B5FC19DB6DBDDD179FD76BB28E850644FD76290C14F9396A3E7F671E07367DBFB5E3407CFF4CC7F51F33374C7223AEDBE355A35FB885827CF16FBDAFDEF828270EC4FC9A51B63CD3FD50C15C75E4E8E7562F26FD2033E010795F49D78A5D0A9AED8025DC79F3F1BAE73D31A641FBDD568AF8D441CB158B8041B18FD4E60FD174BF3DC2E0CDC618DEA6CF33736FE27F2D8B7CD496BC907874B15628BE15F123BB2C6DF843F488DAEACB160FADE69F6A32015B5167636C6A0EB067164B8E9DC1D35762C02E05DF8E537F58E905FCB13341353966F08E2669CB21C505F9F1C1079A989223FD338DEFD6017EF3C0B39CDAA01CE7EA1FD3CB7CD5084D1B131B17041EC30DBF376D7C40AEACC7870E797DE794C7794629A61E9934FDF2B9A7A6CAB1DDFDD425C936C5C3E26B17EF6E99BA4711D46420B2BEBBCE0FCEBBDAC538A4325C96E019FD803CDA51BF7FE1F72AE2CB5AFB092BDC48F4AF715C83CFBED2E361262CB8ECC61862C0125BACEBD22D0BAC77139243ED3348A6DDA4E95BFBC93B4A4CBF2D4311F71B2977D37597072A2DB796BC1BA71D20955F1A7AD635FFD681ED0AD11F8A6D5FD9FD921C786F9B125EF4713222E8A48F76DD4EE58B6A7B33D07F68AF7C3894F7AC7E0DD756A7735F509EF6DEB0CFDB409D22BF799A19141FB9FFC4BD800223DB4E95F0BE1397FB54BE4DEB270C9C1DCADB3E77E4505ABD8ADDE6E4F6DF4F17D5504302263617E4ECB2DD9DF0C924DF75DAB5B4A978EEC7C151EDD59F7C2FEB06B0AEA82F06DCC203848FC0A8FD40E944D6DCF73E643568D5F444FEE4646C466688D55BCF666F434672D53C70383FD5DD846AE09D5B37F23D887F59453F41CF8ED5F666F3EBF55AEBF63DB3E94A4720AED5C72BCDB428B214165E0348B0537ADA3EE2E1C5FBC754C03F0148DA41C1]]>
          </SampleData>
        </SampleImport>
      </Producers>
    </Sample>
    <Mesh Name="GridMesh">
      <Producers>
        <MeshBox Scale="8 8 1" Grid2DOnly="255"/>
        <MeshTransform Rotation="-0.25 0 0"/>
      </Producers>
    </Mesh>
    <Bitmap Name="GridBitmap" Width="2" Height="2" Filter="1">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

if(X+Y == 1)Pixel = 1; else Pixel.B = 1;]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Material Name="GridMaterial" Shading="1" Light="0">
      <Textures>
        <MaterialTexture Texture="GridBitmap" TextureScale="8 8 1" TextureWrapMode="1" TexCoords="1"/>
      </Textures>
    </Material>
  </Content>
</ZApplication>
I'm also setting the panning of the sound based on the relative position and camera rotation .. just in case you were going to ask that next :wink:

K
jinxtengu
Posts: 122
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Sound volume based on distance

Post by jinxtengu »

Thanks again.
Yes, this is almost exactly what I was looking for, although, I notice that the sound ceases entirely when the player is directly over the top of the source of the sound. Is that because it's clipping a value of 1?
User avatar
Kjell
Posts: 1883
Joined: Sat Feb 23, 2008 11:15 pm

Re: Sound volume based on distance

Post by Kjell »

Hi jinxtengu,
jinxtengu wrote: Tue May 09, 2023 9:15 amI notice that the sound ceases entirely when the player is directly over the top of the source of the sound. Is that because it's clipping a value of 1?
Whoops .. forgot to abs() the result of log2() :oops: Change the volume assignment line in Cricket.OnUpdate to ..

Code: Select all

CricketSound.Volume = clamp(1/abs(log2(s)), 0, 1);
K
jinxtengu
Posts: 122
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Sound volume based on distance

Post by jinxtengu »

Many thanks for the update!! :D
Post Reply