Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions Common/ac/audiocliptype.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
namespace AGS { namespace Common { class Stream; } }
using namespace AGS; // FIXME later

#define AUDIO_CLIP_TYPE_SOUND 1
struct AudioClipType {
int id;
int reservedChannels;
int volume_reduction_while_speech_playing;
int crossfadeSpeed;
int reservedForFuture;
struct AudioClipType
{
int id = -1;
int reservedChannels = 0;
int volume_reduction_while_speech_playing = 0;
int crossfadeSpeed = 0;
int reservedForFuture = 0;

AudioClipType() = default;
AudioClipType(int id_, int chans, int for_speech_reduction)
: id(id_), reservedChannels(chans), volume_reduction_while_speech_playing(for_speech_reduction)
{}

void ReadFromFile(Common::Stream *in);
void WriteToFile(Common::Stream *out);
Expand Down
3 changes: 3 additions & 0 deletions Common/ac/common_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,7 @@
// An identifier of a "null font", a pseudo font used when you don't want a text to be drawn
#define FONT_NULL (-1)

// Fixed audio clip type for speech (voice-over)
#define AUDIO_CLIP_TYPE_SPEECH 0

#endif // __AC_DEFINES_H
2 changes: 1 addition & 1 deletion Common/ac/dynobj/scriptaudioclip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void ScriptAudioClip::ReadFromFile(Stream *in)
id = in->ReadInt32();
scriptName.ReadCount(in, LEGACY_AUDIOCLIP_SCRIPTNAMELENGTH);
fileName.ReadCount(in, LEGACY_AUDIOCLIP_FILENAMELENGTH);
bundlingType = static_cast<uint8_t>(in->ReadInt8());
bundlingType = static_cast<AudioClipBundlingType>(in->ReadInt8());
type = static_cast<uint8_t>(in->ReadInt8());
fileType = static_cast<AudioFileType>(in->ReadInt8());
defaultRepeat = in->ReadInt8();
Expand Down
22 changes: 17 additions & 5 deletions Common/ac/dynobj/scriptaudioclip.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,35 @@ enum AudioFileType {
eAudioFileMOD = 6
};

#define AUCL_BUNDLE_EXE 1
#define AUCL_BUNDLE_VOX 2
// Bundling type tells where to look for the audio asset
enum AudioClipBundlingType
{
kAudioBundle_Undefined = 0,
kAudioBundle_GamePak = 1,
kAudioBundle_AudioVox = 2,
kAudioBundle_SpeechVox = 3, // for voice-overs
};

#define LEGACY_AUDIOCLIP_SCRIPTNAMELENGTH 30
#define LEGACY_AUDIOCLIP_FILENAMELENGTH 15

struct ScriptAudioClip {
int id = 0;
struct ScriptAudioClip
{
int id = -1;
Common::String scriptName;
Common::String fileName;
uint8_t bundlingType = AUCL_BUNDLE_EXE;
AudioClipBundlingType bundlingType = kAudioBundle_GamePak;
uint8_t type = 0;
AudioFileType fileType = eAudioFileOGG;
char defaultRepeat = 0;
short defaultPriority = 50;
short defaultVolume = 100;

ScriptAudioClip() = default;
ScriptAudioClip(uint8_t type_, const Common::String &script_name, const Common::String &file_name, AudioClipBundlingType bundle_type)
: type(type_), scriptName(script_name), fileName(file_name), bundlingType(bundle_type)
{}

void ReadFromFile(Common::Stream *in);
};

Expand Down
40 changes: 24 additions & 16 deletions Common/game/main_game_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,15 +452,15 @@ void BuildAudioClipArray(const std::vector<String> &assets, std::vector<ScriptAu
{
clip.scriptName.Format("aMusic%d", temp_number);
clip.fileName.Format("music%d.%s", temp_number, temp_extension);
clip.bundlingType = (ags_stricmp(temp_extension, "mid") == 0) ? AUCL_BUNDLE_EXE : AUCL_BUNDLE_VOX;
clip.bundlingType = (ags_stricmp(temp_extension, "mid") == 0) ? kAudioBundle_GamePak : kAudioBundle_AudioVox;
clip.type = 2;
clip.defaultRepeat = 1;
}
else if (ags_stricmp(temp_name, "sound") == 0)
{
clip.scriptName.Format("aSound%d", temp_number);
clip.fileName.Format("sound%d.%s", temp_number, temp_extension);
clip.bundlingType = AUCL_BUNDLE_EXE;
clip.bundlingType = kAudioBundle_GamePak;
clip.type = 3;
clip.defaultRepeat = 0;
}
Expand Down Expand Up @@ -574,23 +574,31 @@ void UpgradeFonts(GameSetupStruct &game, GameDataVersion data_ver)
void UpgradeAudio(GameSetupStruct &game, LoadedGameEntities &ents, GameDataVersion data_ver)
{
if (data_ver >= kGameVersion_320)
return;

// Create new-style audioClipTypes array.
std::vector<AudioClipType> audiocliptypes;
// FIXME: use audio type constants instead of obscure numeric literals
// (maybe music, sound, ambient sound, voice???)
audiocliptypes.resize(4);
for (int i = 0; i < 4; i++)
{
audiocliptypes[i].reservedChannels = 1;
audiocliptypes[i].id = i;
audiocliptypes[i].volume_reduction_while_speech_playing = 10;
// Ensure the fixed audio type for speech is properly configured
if (game.audioClipTypes.size() < 1)
{
game.audioClipTypes.emplace_back(0 /* id */, 1 /* channels */, 0 /* vol reduction */);
}
}
audiocliptypes[3].reservedChannels = 0;
else
{
// Create new-style audioClipTypes array.
std::vector<AudioClipType> audiocliptypes;
// FIXME: use audio type constants instead of obscure numeric literals
// (maybe music, sound, ambient sound, voice???)
audiocliptypes.resize(4);
for (int i = 0; i < 4; i++)
{
audiocliptypes[i].reservedChannels = 1;
audiocliptypes[i].id = i;
audiocliptypes[i].volume_reduction_while_speech_playing = 10;
}
audiocliptypes[3].reservedChannels = 0;

// Assign new types to the game
game.audioClipTypes = audiocliptypes;
// Assign new types to the game
game.audioClipTypes = std::move(audiocliptypes);
}
}

void ScanOldStyleAudio(AssetManager *asset_mgr, GameSetupStruct &game, std::vector<ViewStruct> &views, GameDataVersion data_ver)
Expand Down
6 changes: 6 additions & 0 deletions Common/util/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ namespace Math
return std::fmod(degrees, 360.0);
return std::fmod(360.0 + degrees, 360.0);
}

// Converts a value from the 255-based range to a 100-based range (with precision loss!)
inline int Range255To100(int value255)
{
return value255 * 100 / 255;
}
} // namespace Math

} // namespace Common
Expand Down
2 changes: 2 additions & 0 deletions Editor/AGS.Editor/AGSEditor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="agsico-1.ico" />
<EmbeddedResource Include="Resources\tree_audio_fixed.ico" />
<EmbeddedResource Include="Resources\wizard-bg.png" />
<EmbeddedResource Include="Resources\wizard-cup.png" />
<EmbeddedResource Include="Resources\menu_build_openfolder.over.ico" />
Expand Down Expand Up @@ -908,6 +909,7 @@
<None Include="Resources\eye.png" />
<None Include="Resources\eye closed.png" />
<EmbeddedResource Include="Resources\exportmask.png" />
<EmbeddedResource Include="Resources\folder_locked.ico" />
<Content Include="Resources\keyword.ico" />
<Content Include="Resources\define.ico" />
<None Include="Resources\lock open.png" />
Expand Down
57 changes: 45 additions & 12 deletions Editor/AGS.Editor/Components/AudioComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ class AudioComponent : BaseComponentWithFolders<AudioClip, AudioClipFolder>, IPr
private const string COMMAND_PROPERTIES_CLIP_TYPE = "PropertiesAudioClipType";

private const string AUDIO_CLIP_TYPE_ICON = "AGSAudioClipTypeIcon";
private const string AUDIO_CLIP_TYPE_FIXED_ICON = "AGSAudioClipTypeFixedIcon";

private const string AUDIO_FILES_FILTER = "All supported audio (*.ogg; *.mp3; *.wav; *.voc; *.mid; *.mod; *.xm; *.s3m; *.it)|*.ogg;*.mp3;*.wav;*.voc;*.mid;*.mod;*.xm;*.s3m;*.it|OGG digital sound file (*.ogg)|*.ogg|MP3 file (*.mp3)|*.mp3|WAV uncompressed audio (*.wav)|*.wav|Creative Labs VOC (*.voc)|*.voc|MIDI music (*.mid)|*.mid|Digital tracker formats (*.mod; *.xm; *.s3m; *.it)|*.mod;*.xm;*.s3m;*.it";
private const int DEFAULT_AUDIO_TYPE_SPEECH = 0;
private const int DEFAULT_AUDIO_TYPE_AMBIENT = 1;
private const int DEFAULT_AUDIO_TYPE_MUSIC = 2;
private const int DEFAULT_AUDIO_TYPE_SOUND = 3;

Expand Down Expand Up @@ -73,6 +76,7 @@ public AudioComponent(GUIController guiController, AGSEditor agsEditor)
_guiController.RegisterIcon("AGSAudioClipIconVoc", Resources.ResourceManager.GetIcon("audio-voc.ico"));
_guiController.RegisterIcon("AGSAudioSpeechIcon", Resources.ResourceManager.GetIcon("audio_speech.ico"));
_guiController.RegisterIcon(AUDIO_CLIP_TYPE_ICON, Resources.ResourceManager.GetIcon("tree_audio_generic.ico"));
_guiController.RegisterIcon(AUDIO_CLIP_TYPE_FIXED_ICON, Resources.ResourceManager.GetIcon("tree_audio_fixed.ico"));
_guiController.ProjectTree.AddTreeRoot(this, TOP_LEVEL_COMMAND_ID, "Audio", "AGSAudioClipsIcon");
_guiController.ProjectTree.OnAfterLabelEdit += new ProjectTree.AfterLabelEditHandler(ProjectTree_OnAfterLabelEdit);
RePopulateTreeView();
Expand Down Expand Up @@ -238,6 +242,12 @@ private void DeleteAudioClipType(AudioClipType typeToDelete)
return;
}

if (typeToDelete.FixedType)
{
_guiController.ShowMessage("You cannot delete this fixed audio type, it is required for the game to function properly.", MessageBoxIconType.Warning);
return;
}

if (typeToDelete.BackwardsCompatibilityType)
{
if (_guiController.ShowQuestion("This audio type is required for backwards compatibility with old-style audio scripting. If you delete it, commands like PlayMusic and PlayAmbientSound will no longer work correctly. Are you sure you want to continue?", System.Windows.Forms.MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
Expand Down Expand Up @@ -314,7 +324,7 @@ private AudioClipType FindAudioClipTypeByNodeID(string nodeID, bool mustFind)
private void CreateNewAudioClipType()
{
_guiController.ProjectTree.StartFromNode(this, AUDIO_TYPES_FOLDER_NODE_ID);
AudioClipType newClipType = new AudioClipType(_agsEditor.CurrentGame.AudioClipTypes.Count + 1, "New audio type", 0, 0, false, CrossfadeSpeed.No);
AudioClipType newClipType = new AudioClipType(_agsEditor.CurrentGame.AudioClipTypes.Count + 1, "New audio type", 0, 0, CrossfadeSpeed.No);
_agsEditor.CurrentGame.AudioClipTypes.Add(newClipType);
string newNodeID = AddTreeNodeForAudioClipType(newClipType);
_guiController.ProjectTree.BeginLabelEdit(this, newNodeID);
Expand Down Expand Up @@ -499,6 +509,10 @@ public override void RefreshDataFromGame()
{
CreateDefaultAudioClipTypes();
}
else
{
EnsureFixedAudioClipTypes();
}

IList<AudioClip> allAudio = null;

Expand All @@ -516,7 +530,10 @@ public override void RefreshDataFromGame()
{
allAudio = _agsEditor.CurrentGame.RootAudioClipFolder.GetAllAudioClipsFromAllSubFolders();
}
AudioClipTypeTypeConverter.SetAudioClipTypeList(_agsEditor.CurrentGame.AudioClipTypes);

// Generate a list of audio types excluding Speech
AudioClipTypeTypeConverter.SetAudioClipTypeList(
_agsEditor.CurrentGame.AudioClipTypes.Where(t => t.TypeID != DEFAULT_AUDIO_TYPE_SPEECH).ToList());
AudioClipTypeConverter.SetAudioClipList(allAudio);

RePopulateTreeView();
Expand Down Expand Up @@ -570,9 +587,18 @@ private void UpdateViewFrameSounds(IList<AudioClip> allAudio, ViewFolder views)

private void CreateDefaultAudioClipTypes()
{
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(1, "Ambient Sound", 1, 0, true, CrossfadeSpeed.No));
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(DEFAULT_AUDIO_TYPE_MUSIC, "Music", 1, 30, true, _agsEditor.CurrentGame.Settings.CrossfadeMusic));
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(DEFAULT_AUDIO_TYPE_SOUND, "Sound", 0, 0, false, CrossfadeSpeed.No));
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(DEFAULT_AUDIO_TYPE_SPEECH, "Speech", 1, 0, CrossfadeSpeed.No));
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(DEFAULT_AUDIO_TYPE_AMBIENT, "Ambient Sound", 1, 0, CrossfadeSpeed.No, backwardsCompatType: true));
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(DEFAULT_AUDIO_TYPE_MUSIC, "Music", 1, 30, _agsEditor.CurrentGame.Settings.CrossfadeMusic, backwardsCompatType: true));
_agsEditor.CurrentGame.AudioClipTypes.Add(new AudioClipType(DEFAULT_AUDIO_TYPE_SOUND, "Sound", 0, 0, CrossfadeSpeed.No));
}

private void EnsureFixedAudioClipTypes()
{
if (_agsEditor.CurrentGame.AudioClipTypes.FirstOrDefault(t => t.TypeID == DEFAULT_AUDIO_TYPE_SPEECH) == null)
{
_agsEditor.CurrentGame.AudioClipTypes.Insert(0, new AudioClipType(DEFAULT_AUDIO_TYPE_SPEECH, "Speech", 1, 0, CrossfadeSpeed.No, fixedType: true));
}
}

private void ImportSoundAndMusicFromOldVersion()
Expand Down Expand Up @@ -925,9 +951,13 @@ public override IList<MenuCommand> GetContextMenu(string controlID)
}
else if (controlID.StartsWith(NODE_ID_PREFIX_CLIP_TYPE))
{
menu.Add(new MenuCommand(COMMAND_RENAME_CLIP_TYPE, "Rename", null));
menu.Add(new MenuCommand(COMMAND_DELETE_CLIP_TYPE, "Delete", null));
menu.Add(MenuCommand.Separator);
AudioClipType typeItem = FindAudioClipTypeByNodeID(_rightClickedID, true);
if (!typeItem.FixedType)
{
menu.Add(new MenuCommand(COMMAND_RENAME_CLIP_TYPE, "Rename", null));
menu.Add(new MenuCommand(COMMAND_DELETE_CLIP_TYPE, "Delete", null));
menu.Add(MenuCommand.Separator);
}
menu.Add(new MenuCommand(COMMAND_PROPERTIES_CLIP_TYPE, "Properties", null));
}
else if (controlID == AUDIO_TYPES_FOLDER_NODE_ID)
Expand Down Expand Up @@ -1017,20 +1047,23 @@ protected override bool CanFolderBeDeleted(AudioClipFolder folder)

protected override void AddExtraManualNodesToTree()
{
_guiController.ProjectTree.AddTreeLeaf(this, SPEECH_NODE_ID, "Speech", "AGSAudioSpeechIcon");
_guiController.ProjectTree.AddTreeBranch(this, AUDIO_TYPES_FOLDER_NODE_ID, "Types", "GenericFolderIcon");
_guiController.ProjectTree.AddTreeBranch(this, AUDIO_TYPES_FOLDER_NODE_ID, "Types", "FixedFolderIcon");
_guiController.ProjectTree.StartFromNode(this, AUDIO_TYPES_FOLDER_NODE_ID);
foreach (AudioClipType clipType in _agsEditor.CurrentGame.AudioClipTypes)
{
AddTreeNodeForAudioClipType(clipType);
}
_guiController.ProjectTree.StartFromNode(this, TOP_LEVEL_COMMAND_ID);
_guiController.ProjectTree.AddTreeLeaf(this, SPEECH_NODE_ID, "Speech", "AGSAudioSpeechIcon");
}

private string AddTreeNodeForAudioClipType(AudioClipType clipType)
{
string newNodeID = GetClipTypeNodeID(clipType);
ProjectTreeItem treeItem = (ProjectTreeItem)_guiController.ProjectTree.AddTreeLeaf(this, newNodeID, clipType.Name, AUDIO_CLIP_TYPE_ICON);
treeItem.AllowLabelEdit = true;
// TODO: figure out how to make certain properties (like Name) readonly only in the "fixed" type
ProjectTreeItem treeItem = (ProjectTreeItem)_guiController.ProjectTree.AddTreeLeaf(this, newNodeID, clipType.Name,
clipType.FixedType ? AUDIO_CLIP_TYPE_FIXED_ICON : AUDIO_CLIP_TYPE_ICON);
treeItem.AllowLabelEdit = !clipType.FixedType;
treeItem.LabelTextProperty = clipType.GetType().GetProperty("Name");
treeItem.LabelTextDescriptionProperty = clipType.GetType().GetProperty("Name");
treeItem.LabelTextDataSource = clipType;
Expand Down
3 changes: 3 additions & 0 deletions Editor/AGS.Editor/Components/BaseComponent.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AGS.Types;
using System;
using System.Collections.Generic;
using AGS.Editor.Resources;
using System.Text;

namespace AGS.Editor.Components
Expand All @@ -16,6 +17,8 @@ protected BaseComponent(GUIController guiController, AGSEditor agsEditor)
{
_guiController = guiController;
_agsEditor = agsEditor;

_guiController.RegisterIcon("FixedFolderIcon", ResourceManager.GetIcon("folder_locked.ico"));
}

public virtual void CommandClick(string controlID)
Expand Down
16 changes: 5 additions & 11 deletions Editor/AGS.Editor/DataFileWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1751,19 +1751,13 @@ public static bool SaveThisGameToFile(string fileName, Game game, CompileMessage
{
FilePutNullTerminatedString(game.Dialogs[i].Name, writer);
}
writer.Write(game.AudioClipTypes.Count + 1);
// hard coded SPEECH audio type 0
writer.Write(0); // id
writer.Write(1); // reservedChannels
writer.Write(0); // volume_reduction_while_speech_playing
writer.Write(0); // crossfadeSpeed
writer.Write(0); // reservedForFuture
for (int i = 1; i < (game.AudioClipTypes.Count + 1); ++i)
writer.Write(game.AudioClipTypes.Count);
for (int i = 0; i < (game.AudioClipTypes.Count); ++i)
{
writer.Write(i); // id
writer.Write(game.AudioClipTypes[i - 1].MaxChannels); // reservedChannels
writer.Write(game.AudioClipTypes[i - 1].VolumeReductionWhileSpeechPlaying); // volume_reduction_while_speech_playing
writer.Write((int)game.AudioClipTypes[i - 1].CrossfadeClips); // crossfadeSpeed
writer.Write(game.AudioClipTypes[i].MaxChannels); // reservedChannels
writer.Write(game.AudioClipTypes[i].VolumeReductionWhileSpeechPlaying); // volume_reduction_while_speech_playing
writer.Write((int)game.AudioClipTypes[i].CrossfadeClips); // crossfadeSpeed
writer.Write(0);
}
IList<AudioClip> allClips = game.AudioClips;
Expand Down
2 changes: 1 addition & 1 deletion Editor/AGS.Editor/Resources/agsdefns.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3207,7 +3207,7 @@ builtin struct Game {
#endif // SCRIPT_API_v340
#ifdef SCRIPT_API_v350
/// Play speech voice-over in non-blocking mode, optionally apply music and sound volume reduction
import static AudioChannel* PlayVoiceClip(Character*, int cue, bool as_speech = true);
import static AudioChannel* PlayVoiceClip(Character*, int cue, bool as_speech=true, AudioPriority=SCR_NO_VALUE, RepeatStyle=SCR_NO_VALUE);
/// Simulate a keypress on the keyboard.
import static void SimulateKeyPress(eKeyCode key);
#endif // SCRIPT_API_v350
Expand Down
Binary file added Editor/AGS.Editor/Resources/folder_locked.ico
Binary file not shown.
Binary file added Editor/AGS.Editor/Resources/tree_audio_fixed.ico
Binary file not shown.
Loading